我还在学习angularjs,我对理解$scope
和model
对象之间的差异有疑问,这当前阻止我组织(使用一些最佳实践)我的应用程序。
据我所知,$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#world,在那里我总是使用实体对象(例如User,Product,Item等)在循环中填充这些对象并将其存储在列表中。我无法找到一种方法,我应该如何在角度中使用这种方法,如果是的话应该仅使用属性服务?
我使用一个服务来保持列表,一个服务包含CRUD函数。
如果我从我的模型中加载 $scope
中的数据,如果代码的其他部分更改模型中的数据,如何更新该范围?
更改可以来自另一个控制器,也可以通过SignalR进行更新。
另外,正如我所知,当我更新$scope
视图上的数据应该只读更新时我需要更新服务,然后再次更新$scope
的方式和时间?
我很抱歉,如果我的问题太棒了,但是如果有人可以帮助我理解在哪里保持角度,我会感激不尽?
答案 0 :(得分:4)
该模型更常用于名为Model-view-controller(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 CODE1 FULL CODE2)
我对理解$ scope和model之间的区别有疑问 对象
范围只是在我们看到时参考模型,但不是模型!范围也用于用户交互,控制器取决于范围,控制器取决于模型。
所以我可以用缓存的方式操作这个列表(保持它本地并更新它 偶尔)?
有很多方法可以解决这个问题。我们经常使用观察者模式,但在角度方面,还有另一种方法可以做到这一点,在大多数情况下更好。这是一个例子:
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 :(得分:2)
问题: 你有一些远程数据。您希望所有控制器都可以访问它。你不希望他们每个人都自己得到它。
在Angular中执行此操作的一种方法: 使用服务。服务都是单身人士。这意味着您的应用程序将只有一个服务实例,可用于共享数据。我查看了您分享的链接,以下是第二个建议的示例,&#34;服务是模型和服务&#34;。
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 :(得分:2)
Angular没有一种存储数据的固定方式。
已解决此问题和其他相关问题的一些项目:
https://github.com/mgonto/restangular
https://github.com/adrianlee44/ng-backbone
https://github.com/paysavvy/immutable-angular
我过去所做的是编写一个存储数据的models
和collections
模块。这些只是简单的构造函数。
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>
答案 3 :(得分:1)
我没有阅读完全相同的教程,但我通常会参考John Papa最初发表的Angular Style Guide,并得到Angular社区的大量反馈。
如果您使用SignalR实时更新模型,我认为您正在寻找的是单向数据流的概念。我没有很好的资源可以指出这一点,但我已经看到了一些SignalR和Angular的例子,你可能会发现它们只是寻找基本的想法。
总的来说,目标是从服务器到您的应用程序进行更新。因此,如果控制器更新了某个值,则控制器代码不会更新您的数据模型。您的应用程序向服务器发送写入,服务器将新值发送回AngularJS应用程序。
1.5之前的Angular版本没有单向数据绑定的概念,所以如果你使用ng-model双向绑定是自动的,那么你通常需要将你绑定的值视为临时然后在用户完成编辑数据时将状态与缓存值或服务器同步。
您的问题非常广泛,所以如果您想要更具体的答案或操作方法,您可能希望包含一些有关您正在编写的应用程序类型的信息,有时还包括应用程序的大小(控制器数量) /功能)将了解哪些实践将为您提供最佳服务。对于非常大的应用程序,一些最佳实践看起来像简单的周末项目应用程序的反模式。