在AngularJS中模块之间发送数据的正确方法是什么?

时间:2016-10-26 14:09:35

标签: javascript angularjs

角度的一个好处是你可以拥有可以在不同地方重复使用的独立模块。假设您有一个模块可以使用列表进行绘制,排序和执行许多操作。假设此模块将在您的应用程序周围使用。最后,说你想以不同的方式填充它。这是一个例子:

angular.module('list', []).controller('listController', ListController);
var app = angular.module('myapp', ['list']).controller('appController', AppController);

function AppController() {
  this.name = "Misae";
  this.fetch = function() {
    console.log("feching");
    //change ListController list
    //do something else
  }
}

function ListController() {
  this.list = [1, 2, 3];
  this.revert = function() {
    this.list.reverse();
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="app" ng-app="myapp" ng-controller="appController as App">

  <div class="filters">
    Name:
    <input type="text" ng-model="App.name" />
    <button ng-click="App.fetch()">Fetch</button>
  </div>

  <div class="list" ng-controller="listController as List">
    <button ng-click="List.revert()">Revert</button>
    <ul>
      <li ng-repeat="item in List.list">{{item}}</li>
    </ul>
  </div>

</div>

现在,当您单击“获取”按钮时,您将使用$http将名称(以及其他过滤器和内容)发送到API,依此类推。然后你会得到一些数据,包括你想要绘制的项目列表。然后,您希望将该列表发送到要绘制的List模块。

必须这样,因为你将在不同的地方使用列表模块,它将始终绘制一个列表并添加一些功能,如重新排序和反转它。虽然过滤器和API连接会发生变化,但列表行为却不会,因此必须有2个不同的模块。

那就是说,获取数据后将数据发送到List模块的最佳方法是什么?有了服务吗?

10 个答案:

答案 0 :(得分:9)

您应该使用Angular components执行此任务。

您应该创建一个模块,其中包含一个显示列表的组件,并提供一些操作来修改列表并告诉父级更新值。

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

list.controller('listCtrl', function() {
    this.reverse = function() {
        this.items = [].concat(this.items).reverse();
        this.onUpdate({ newValue: this.items });
    };
});

list.component('list', {
  bindings: {
    items: '<',
    onUpdate: '&'
  },
  controller: 'listCtrl',
  template: '<button ng-click="$ctrl.reverse()">Revert</button><ul><li ng-repeat="item in $ctrl.items">{{ item }}</li></ul>'
});

这样,当您单击“Revert”list组件时,将反转数组并执行HTML元素的on-update属性中提供的功能。

然后您可以简单地将您的应用设置为依赖于此模块

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

并使用list组件

<list data-items="list" data-on-update="updateList(newValue)"></list>

您可以在the example

中查看其余代码

答案 1 :(得分:4)

很简单。请看一下这个小片段。添加注释以突出显示。

您可以拥有一个公共模块,其中包含需要跨模块共享的所有数据两步

  • 添加模块依赖
  • 在相应模块的控制器中注入相应的提供程序

&#13;
&#13;
angular.module('commonAppData', []).factory('AppData',function(){
var a,b,c;
  a=1;
  return{
    a:a,
    b:b,
    c:c
  }
})

angular.module('list', ['commonAppData']).controller('listController', ListController);
var app = angular.module('myapp', ['list','commonAppData']).controller('appController', AppController);

function AppController(AppData) {
  //assigning a variable
  AppData.a=100;
  
  this.name = "Misae";
  this.fetch = function() {
    console.log("feching");
    //change ListController list
    //do something else
  }
}

function ListController(AppData) {
  //Using the data sent by App Controller
  this.variableA=AppData.a;
  
  this.list = [1, 2, 3];
  this.revert = function() {
    this.list.reverse();
  }
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="app" ng-app="myapp" ng-controller="appController as App">

  <div class="filters">
    Name:
    <input type="text" ng-model="App.name" />
    <button ng-click="App.fetch()">Fetch</button>
  </div>

  <div class="list" ng-controller="listController as List">
    <b>Shared variable : {{List.variableA}}</b>
    <br>
    <button ng-click="List.revert()">Revert</button>
    <ul>
      <li ng-repeat="item in List.list">{{item}}</li>
    </ul>
  </div>

</div>
&#13;
&#13;
&#13;

答案 2 :(得分:3)

有几种方法可以处理多个控制器的对象。这是两个。

<强> 1。使用Angulars $rootScope

您可以将对象分配给$rootScope,这将保留所有信息。可以通过Angulars依赖注入将此对象传递到每个控制器。此外,您可以通过$watch$emit观看对象的最新动态。

使用$rootScope是一种简单的方法,但可能会导致较大的应用程序出现性能问题。

<强> 2。使用服务

Angular提供了通过服务共享对象的可能性。您也可以在服务中执行此操作,而不是在控制器内定义对象。这样做可以将该服务注入任何控制器并在整个应用程序中使用它。

function AppController(listService) {
  // reference to the injected data
}

function ListController(listService) {
  // update data
}

答案 3 :(得分:1)

AngularJS为控制器之间的基于事件的通信提供$on$emit$broadcast服务。

因此,如果我们想将数据从内部控制器( listController )传递到外部控制器( appController ),那么我们必须使用$emit。它通过范围层次结构向上调度事件名称,并通知已注册的$rootScope

Working Plunker: https://plnkr.co/edit/szf9jHvvOPLOvQc5sQI2?p=preview

这个plunker不是按照我不知道api响应的确切要求,但是这个样本plunker描述了问题陈述,我希望它能帮到你。

感谢。

答案 4 :(得分:1)

这取决于具体情况。有亲子关系吗?这种关系是未知的,或者你只是想避免不必担心它?

我认为这篇文章很好地解决了(它似乎总是有用):

http://mean.expert/2016/05/21/angular-2-component-communication/

答案 5 :(得分:1)

有很多方法可以将数据从一个模块传递到另一个模块,很多人提出了不同的方法。

最好的方法和清洁方法之一是使用factory而不是污染$rootScope or using $emit or $broadcast or $controller。如果您想了解有关如何使用所有这些的更多信息,请访问此blog 以角度js

访问另一个控制器的功能

只需注入您在主模块中创建的工厂,并在主模块中添加子模块作为依赖项,然后在子模块中注入工厂以访问工厂对象。

以下是有关如何使用工厂在整个应用程序中共享数据的示例example

让我们创建一个工厂,可以在所有控制器的整个应用程序中使用它来存储数据并访问它们。

工厂的优点是你可以在其中创建对象并在控制器中的任何位置初始化它们,或者我们可以通过在工厂本身初始化它们来设置defult值。

<强>工厂

app.factory('SharedData',['$http','$rootScope',function($http,$rootScope){

    var SharedData = {}; // create factory object...
    SharedData.appName ='My App';
    return SharedData;
}]);

<强>服务

app.service('Auth', ['$http', '$q', 'SharedData', function($http, $q,SharedData) {
   this.getUser = function() {

            return $http.get('user.json')
              .then(function(response) {
                  this.user = response.data;
                  SharedData.userData = this.user; // inject in the service and create a object in factory ob ject to store user data..
                  return response.data;
              }, function(error) {
                  return $q.reject(error.data);
              });

    };

}]);

<强>控制器

var app = angular.module("app", []);
app.controller("testController", ["$scope",'SharedData','Auth',
  function($scope,SharedData,Auth) {

    $scope.user ={};
   // do a service call via service and check the shared data which is factory object ...
   var user = Auth.getUser().then(function(res){
       console.log(SharedData);
       $scope.user = SharedData.userData;// assigning to scope.
   });


  }]);

在HTML中

<body ng-app='app'>
    <div class="media-list" ng-controller="testController">

       <pre> {{user | json}}</pre>

    </div>

</body>

答案 6 :(得分:0)

我认为您可以使用$ rootScope中实现的发布者 - 订阅者模式。

在ListController中你必须注入$ rootScope,然后你必须订阅一个任意的被调用的事件,它可以具有模式_data_received

$rootScope.$on('ingredients_data_received', function(ingredients) { prepare_recipe();});

所以在你的AppController中,你必须在收到该列表的数据后调用$ rootScope。$ emit

$rootScope.$emit('ingredients_data_received', ingredients);

这只是传递数据的一种方式,您也可以在$ rootScope属性中推送这些数据或承诺,但这不是一个好习惯,或者您可以创建自己的服务来为您管理数据(请记住您正在使用前端框架,因此控制器必须控制视图,业务逻辑必须转移到服务,而不是转移到crontroller。)

答案 7 :(得分:0)

1)如果你想要非持久性数据,一种方法是使用服务。

app.service('yourService', function() {
   this.setData = function(value) {
     this.params = value;
   }

    this.getData = function () {
        return this.params;
    }
});

类似服务是一种单例数据,可以从一个模块中分配服务,然后恢复到另一个模块。

http://www.w3schools.com/angular/angular_services.asp

2)如果您希望持久保存数据,可以使用本地存储或indexDB。就像每个模块都可以访问持久化数据一样:

localStorage的样本

window.localStorage.setItem("attribute", "value");
window.localStorage.getItem("attribute");

http://www.w3schools.com/html/html5_webstorage.asp

答案 8 :(得分:0)

我喜欢使用带有缓存层的角度资源,使用单一方法将数据持久化到多个控制器。这有一些好处,即任何控制器都具有相同的数据入口点。请记住,有时您需要在从站点的一部分导航到另一部分时获取新数据,因此持久的http数据并不总是理想的。

'use strict';
(function() {
    angular.module('customModule')
        .service('BookService', BookService);

    BookService.$inject = ['$resource'];

    function BookService($resource) {
        var BookResource = $resource('/books', {id: '@id'}, {
            getBooks: {
                method: 'GET',
                cache: true
            }
        });

        return {
            getBooks: getBooks
        };

        function getBooks(params) {
            if (!params) {
                params = {};
            }
            return BookResource.getBooks(params).$promise;
        }
    }
})();

在任何控制器中

BookService.getBooks().then(function(books) {
    //books will be cached so invoking the call will return the same set of data anywhere
});

答案 9 :(得分:0)

角度中的

Services用于在组件之间共享功能。请尽量保持简单,只有一个责任/目的。 一个想法是创建一个store服务,它将缓存应用程序中api的每个响应。那么你不必每次都要求它。

希望它有所帮助! ;)