2016-04-30 70 views
6

我仍然在学习angularjs,我有问题$scopemodel对象之间的理解差异,这目前阻止我组织(使用一些最佳实践),我的应用程序。
据我所知$scope应该是只读的(看过一些教程,我听到这个)。

所以,当我加载应用程序,我应该使用service从数据库中获取一些数据,并将其存储在model

UPDATE

现在,我从服务器获取的所有数据都存储在控制器$范围,我想将它移动到服务,使控制器笨。
我也检查了这个article,我试图使用第二或第三个选项,但仍然找不到实现它的最佳方法。
这是我的服务和控制器:在angularJS应用程序中保留模型的位置?

function dataService($http) { 
     var service = { 
      getToDoList: getToDoList, 
      getToDoListByType: getToDoListByType, 
      getToDoById: getToDoById 
     }; 

     return service; 

     function getToDoList() { } 
     function getToDoListByType() { } 
     function getToDoById() { } 
    } 
function toDoController($location) {  
     var vm = this; 

     vm.todos = []; 
     vm.title = 'toDoController'; 

     activate(); 

     function activate() { 
      return getToDos().then(function() { 
       console.log("ToDos loaded"); 
      }); 
     } 

     function getToDos() { 
      return dataservice.getToDoList() 
       .then(function (data) { 
        vm.todos = data; 
        return vm.todos; 
       }); 
     } 
    } 

但在这个实施待办事项又是在控制器中。

我应该在哪里,并存储该列表后,我从服务器获取它从那里应设置(从控制器或服务),所以我可以操纵这个列表中缓存的方式(保持它的地方,偶尔更新)?

我从C#世界来了,还有我一直使用的实体对象(如用户,产品,项目等)来填充这些对象在一个循环,并将其存储在列表中。我无法找到一种方法,我应该如何以角度使用这种方法,如果是的话,应该只使用属性服务?

我用一个服务来保持列表和一个服务包含CRUD功能。 如果我从我的模型中加载$scope中的数据,如果稍后更新该范围,如果代码的其他部分更改模型中的数据?

更改可能来自另一个控制器或通过SignalR进行更新。 也正如我听到当我更新数据视图为$scope应该只读,我需要更新服务,并再次如何以及何时更新$scope呢?

对不起,如果我的问题太noob,但我会感激,如果有人可以帮助我了解哪些角度保持什么?

+0

某些时候ToDo列表必须在控制器中,否则您将无法绑定到它。你想要抽象出的是接触到服务的操作,以便如果服务器实现发生更改,则只需更改数据服务,而不是控制器。它还有助于单元测试,因为您可以使模拟数据服务返回假数据。在编写任何服务器代码之前,我也做同样的原型设计。 – nbering

+0

在问题的例子中,我创建了一个抽象服务器调用的服务。我将举另一个例子:'Service获取列表'''返回列表到控制器$ scope'>'显示它的视图'=>但现在在视图中操纵该项目中的数组通过添加一些属性到每个项目(分组,着色等),我需要添加以显示这些数据。假设我不想再次更改所有这些属性(再次运行循环),但我需要从服务器获得的原始数据。但是,当我返回列表控制器我没有原始数组了。 – 1110

+0

因为我不想再次调用服务器,所以我不知道什么是好的做法 - 在哪里保持该模型。 – 1110

回答

4

该模型用于更经常在名为模型 - 视图 - 控制器(MVC)软件架构模式。如果没有全面的模式知识,你无法理解模型是如何工作的。在这种模式中,Web应用程序被分解成组件,目的是分离责任。我将通过一个完整的TODO代码的例子来介绍MVC的真实用途。 enter image description here

模型:获取/操作所有域数据(更经常地从服务器获取)。在这里,您创建了一个清晰的API,可以访问数据,这与服务有关。在服务中,您从服务器获取数据,然后将其保存在内部,然后传递一些可以访问的功能,当某人需要这些数据时,他只需使用注入来访问该服务。把这种服务想象成类似于带有数据,get/set和其他方法的单例类。一条规则是:如果你不知道发生了什么事情,那么更有可能去服务。 (FULL CODE)

.factory('api', function ($resource) { 
    'use strict'; 

    var store = { 
     //HERE IS THE API 
     todos: [], 

     api: $resource('/api/todos/:id', null, 
      { 
       update: { method:'PUT' } 
      } 
     ), 
     clearCompleted: function()[..] 
     delete: function (todo)[..] 
     get: function() [..] 
     insert: function (todo)[..] 
     put: function (todo)[..] 
    }; 
    return store; 
}) 

控制器:在上面的图片中,可以看到简单的控制器只得到,而不是从用户交互放弃。控制器不会操纵Dom。这里的数据通过使用范围(或者在控制器内部使用this)从视图(用户)到控制器,然后使用我们通过注入服务(模型)获得的函数来操作模型。很多时候,我们通过查询模型并将结果传递给视图,使得控制器充当中介,从而打破了MVC的规则,这是一种不同的模式名称MVP。规则是:你的控制器必须始终尽可能精简(FULL CODE

.controller('TodoCtrl', function TodoCtrl($scope, $routeParams, $filter, store) { 
    //store is the model, we make this in app.js 
    //is the result of a factory we make up,and we named "api" 
    var todos = $scope.todos = store.todos; 
    [..] 
    //in html we call removeTODO 
    //<button class="destroy" ng-click="removeTodo(todo)"></button> 
    //We use user interaction to manipulate the model! 
    $scope.removeTodo = function (todo) { 
    store.delete(todo);//we use the api we make 
    }; 
    [..] 

景观:正如你可以在图片中看到,模型更新视图,而不是控制。怎么样?使用指令和过滤器。要小心,视图只能显示数据(数据绑定)。不包含复杂的逻辑。我想清楚,在MVC中,视图应直接访问模型。指令和过滤器提供此功能。如果你想做一个DOM操作,你必须使用一个指令(而不是控制器)。注意:我们把DOM操作指令的编译和链接函数内部,而不是在控制器(FULL CODE1FULL CODE2

我有问题,了解$范围和模式 对象之间的区别

范围只是指我们看到的模型,但不是模型!范围也用于用户交互,控制器取决于范围,控制器取决于模型。

所以我可以用缓存的方式操作这个列表(保持本地并偶尔更新它 )?

有很多方法可以解决这个问题。我们经常使用观察者模式,但是在角度上还有另外一种方法可以做到这一点,在大多数时候更好。这里的一个例子:

angular 
    .module("testApp", []) 
    .service("myDataService", function(){ 
    this.dataContainer = { 
     valA : "car", 
     valB : "bike" 
    } 
    }) 
    .controller("testCtrl", [ 
    "$scope", 
    "myDataService", 
    function($scope, myDataService){ 
     $scope.data = function(){ 
     //you get always the update data and never store tha data 
     //to the controller 
     return myDataService.dataContainer; 
     }; 
    }]); 

欲了解更多信息检查this,有一些惊人的答案。

1

我还没有阅读完全相同的教程,但我通常会参考John Papa最初发布的Angular Style Guide以及来自Angular社区的大量反馈。

如果您使用SignalR实时更新你的模型,我认为你在寻找什么是单向数据流的概念。我没有很好的资源可以指出你的看法,但我已经看到了一些SignalR和Angular的例子,你可能会发现只是寻找基本想法。

总的来说,目标是从服务器到您的应用程序进行更新。所以如果你的控制器更新了一个值,你的数据模型不会被控制器代码更新。您的应用程序将写入发送到服务器,并且服务器将新值发送回AngularJS应用程序。

1之前的角度版本。5没有单向数据绑定的概念,所以如果你使用的是ng-model 2-way绑定是自动的,所以你通常需要将你绑定的值作为临时对象,然后与一个同步状态缓存值或用户完成编辑数据时的服务器。

你的问题是相当广泛的,因此,如果您想更具体的答案或如何,你可能要包括约你写的是什么类型的应用程序,有时应用规模的一些信息(号码控制器/功能)将给出一个想法,哪些实践将最好地为您服务。一些非常大的应用程序的最佳实践看起来像简单的周末项目应用程序的反模式。

+0

嗨,我必须重新打开问题。我更新了更具体的问题。我需要为大型应用程序设置我的应用程序。在这方面没有任何一种导师。我更新的问题包含详细信息 – 1110

2

问题: 您有一些远程数据。你希望所有的控制器都可以访问它。你不希望他们每个人都靠自己获得。

在Angular中执行此操作的一种方法: 使用服务。服务都是单身。这意味着您的应用只会有一个服务实例,可用于共享数据。我查看了您分享的链接,下面是第二个建议“服务是模型和服务”的示例。

function dataService($http) { 
    var todos= []; 
    this.getTodos = function() { return todos; }; 

    this.getToDoList= function() { 
     // use $http to get remote data and assign it to todos 
    }; 
} 

现在你可以做TodoService.getData()的任何地方你已经注射了,说也许你.RUN块,并且从那时起,TodoService.getTodos()将返回服务之前得到了相同的数据。

或者,您可以使用该服务专门为获取数据,而不是存储(你的链接的第3个建议)。要做到这一点,你就不会存储var todos在服务上,还是有this.getTodos,你只会有功能的getData(和其它数据得到的功能)。然后从每个控制器运行TodoService.getData()来运行常见的http get函数。

我应该在哪里存储这个名单后,我从服务器获取它,从它应设置(从控制器或服务),这样我就可以在缓存的方式操纵这个名单(保持它的地方,偶尔更新)?

如果您想以缓存方式存储和操作它,您希望将数据保留在服务中。您的控制器将从服务中获取数据。在using services to talk between controllers上有一堆文章。他们讨论使用$broadcast发送您自己的事件,以便更新到一个控制器将更新其他独立控制器。

无论哪种情况:您确实想要在控制器中将todos列表绑定到$scope。这将允许你在你的视图中输出它的内容,并使用像双向绑定的Angular魔术。在您的代码中:

function toDoController($scope, dataService) {  
    $scope.todos = []; 

    activate(); 

    function activate() { 
     return getToDos().then(function() { 
      console.log("ToDos loaded"); 
     }); 
    }; 

    function getToDos() { 
     return dataService.getToDoList() 
      .then(function (data) { 
       $scope.todos = data; 
       return $scope.todos; 
      }); 
    }; 
} 

然后在您看来,您可以参考{{todos}}

2

Angular不会以自以为是的方式来存储数据。

说已经解决了这个问题和其他相关问题的一些项目:

https://github.com/mgonto/restangular
https://github.com/adrianlee44/ng-backbone
https://github.com/paysavvy/immutable-angular

我过去所做的是写了存储数据的modelscollections模块。这些只是简单的构造函数。

angular 
    .module('app.models', []) 
    .factory('app.models.User', ['$resource', function($resource) { 

    function User(name) { 
     this.name = name; 
    } 

    User.prototype.sayName = function() { 
     console.log(this.name) 
    }; 

    User.prototype.getInfo = function(params) { 
     $resource.get(params).then(res => { 
     this.info = res.data; 
     }); 
    }; 

    return User; 

    }); 

然后在您的视图模型中,您将视图连接到模型!

['app.models.User', function Controller(User) { 
    this.user = new User('bob'); 
}] 

<div> 
    <button ng-click="vm.user.sayName()">say name</button> 
</div>