【问题标题】:Where to keep model in angularJS app?在 angularJS 应用程序中将模型保存在哪里?
【发布时间】:2016-08-25 15:33:17
【问题描述】:

我仍在学习 angularjs,但我无法理解 $scopemodel 对象之间的区别,这目前阻止我组织(使用一些最佳实践)我的应用程序。
据我了解,$scope 应该是只读的(观看了一些我听说过的教程)。

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

更新

现在,我从服务器获取的所有数据都存储在控制器 $scope 中,我正试图将其移至服务并让控制器变得更笨。
我还检查了这个article,我正在尝试使用第二个或第三个选项,但仍然找不到实现它的最佳方法。
这是我的服务和控制器:

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# 世界,在那里我总是使用实体对象(例如用户、产品、项目等)在循环中填充这些对象并将其存储在列表中。我也找不到一种方法,我应该如何在 Angular 中使用这种方法,如果是,那应该是仅具有属性的服务吗?

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

例如,更改可以来自另一个控制器或通过 SignalR 进行更新。 另外,当我更新视图上的数据时,我听说$scope 应该是只读的,我需要更新服务以及如何以及何时更新$scope

如果我的问题太菜鸟,我很抱歉,但如果有人能帮助我了解在哪里保留有角度的内容,我将不胜感激?

【问题讨论】:

  • 在某些时候,ToDo 列表必须在控制器中,否则您将无法绑定到它。您要抽象出的是触及服务的操作,因此如果服务器实现发生更改,您只需要更改数据服务,而不是控制器。它还有助于单元测试,因为您可以制作模拟数据服务来返回假数据。在编写任何服务器代码之前,我也会为原型设计做同样的事情。
  • 在问题示例中,我创建了一个抽象服务器调用的服务。我将举另一个例子:Service gets the list > return list to controller $scope > display it on view => 但现在在视图中,我通过向需要添加的每个项目(分组、着色等)添加一些属性来操作项目中的数组为了显示这些数据。假设我不想再次更改所有这些属性(再次运行循环),但我需要从服务器获得的原始数据。但是当我将列表返回给控制器时,我不再有原始数组了。
  • 因为我不想再次调用服务器,所以我不知道什么是好的做法 - 在哪里保留该模型。
  • 保留你的模型:@C.C.回答。像 angularCache 这样的模块有一些缓存来处理数据过期等等。 sessionStorage 用于最近的浏览器。所有这些元素都必须在 Service 层使用。

标签: javascript angularjs angularjs-scope


【解决方案1】:

该模型更常用于名为模型-视图-控制器 (MVC) 的软件架构模式中。如果不了解完整模式,您将无法理解模型的工作原理。在这种模式中,Web 应用程序被分解成组件,目的是分离职责。我将通过一个完整的 TODO 代码示例指导您了解 MVC 的真正用途。

模型:获取/操作所有域数据(通常是从服务器获取)。在这里,您创建了一个清晰的 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)

我无法理解 $scope 和 model 之间的区别 对象

范围只是我们看到的模型,而不是模型!范围也用于用户交互,控制器依赖于范围,控制器依赖于模型。

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

有很多方法可以解决这个问题。常规我们使用观察者模式,但在 Angular 中,还有另一种在大多数情况下更好的方法。举个例子:

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,有一些惊人的答案。

【讨论】:

    【解决方案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() 将返回服务之前获得的相同数据。

    或者,您可以专门使用该服务来获取数据而不是存储(您的链接的第三条建议)。为此,您不会将var todos 存储在服务中,或者拥有this.getTodos,您将只有getData 函数(和其他数据获取函数)。然后从每个控制器运行 TodoService.getData() 来运行常见的 http get 函数。

    从服务器获取此列表以及应从何处设置(从控制器或从服务)后,我应该将其存储在哪里,以便我可以以缓存的方式操作此列表(将其保留在本地并偶尔更新它)?

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

    在任一情况下:您确实希望将todos 列表绑定到控制器中的$scope。这将允许您在视图中输出其内容并使用 Angular 魔术,如 2-way binding。在您的代码中:

    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}}

    【讨论】:

      【解决方案3】:

      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>
      

      【讨论】:

        【解决方案4】:

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

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

        总体而言,目标是从服务器获取更新到您的应用程序。因此,如果您的控制器更新了一个值,则控制器代码不会更新您的数据模型。您的应用程序向服务器发送一个写入,服务器将新值发送回 AngularJS 应用程序。

        1.5 之前的 Angular 版本没有单向数据绑定的概念,因此如果您使用 ng-model 双向绑定是自动的,因此您通常需要将绑定的值视为临时值然后在用户完成数据编辑时将状态与缓存值或服务器同步。

        您的问题非常广泛,因此如果您想要更具体的答案或操作方法,您可能需要包含一些有关您正在编写的应用程序类型的信息,有时还包括应用程序的大小(控制器的数量) /features) 将提供一个想法,了解哪些做法最适合您。大型应用程序的一些最佳实践似乎是简单周末项目应用程序的反模式。

        【讨论】:

        • 您好,我必须重新提出问题。我更新了问题以更具体。我需要为大型应用程序设置我的应用程序。在这方面没有任何导师。我更新的问题包含详细信息。
        猜你喜欢
        • 1970-01-01
        • 2013-06-19
        • 2011-12-09
        • 1970-01-01
        • 2011-04-09
        • 1970-01-01
        • 1970-01-01
        • 2021-02-15
        • 2021-03-21
        相关资源
        最近更新 更多