I am still learning angularjs and I have problem with understanding difference between $scope
and model
object and this currently block me to organize (use some best practice) my app.
As I understand $scope
should be read only (watched some tutorials where I heard this).
So when I load app I should use service
to get some data from database and store it in model
.
UPDATE
Right now all data that I get from server are stored in controller $scope and I am trying to move it to services and make controller dumber.
I also check this article and I am trying to use second or third option but still can't find best way to implement it.
This is my service and controller:
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;
});
}
}
But in this implementation to do list is again in the controller.
Where should I store this list after I get it from server and from where it should be set (from controller or from service) so I can manipulate this list in a cached way (keep it local and update it occasionally)?
I am coming from C# world and there I always used entity objects (e.g. User, Product, Item etc.) populate those object in a loop and store it in a list. I can't find a way how should I use this approach in angular too and if yes should that be service with properties only?
I use one service to keep the list and one service to contain CRUD functions.
If I load data in $scope
from my model how to update that scope later if some other part of code change data in my model?
Change can come from another controller or be updated via SignalR for example.
Also as I heard when I update data on view as $scope
should be readonly I need to update service and again how and when to update $scope
then?
I am sorry if my question is too noob but I would be thankful if someone can help me to understand where to keep what in angular?
The model in an MVC-based application is generally responsible for modeling the data used in the view and handling user interactions such as clicking on buttons, scrolling, or causing other changes in the view. In basic examples, AngularJS uses the $scope object as the model.
Models in Angular JS are represented by the ng-model directive. The primary purpose of this directive is to bind the view to the model. How to build a simple controller using the ng-app, ng-controller and ng-model directives.
top-level “app” folder : all angular files should be placed within a folder that could be named as “app”. “app” is the top-level folder. app/components folder: one or more components can be placed within “app/components” folder.
The model is used more often in a software architectural pattern named Model–view–controller (MVC). You can't understand how the model works without having a knowledge of the full pattern. In this pattern, the web application is broken into components with the purpose to separate responsibilities. I will direct you with an example of full TODO code to see the real use of MVC.
Model: Take/manipulate all the domain data (more often you take this from the server). Here you create a clear API that gives access to the data, that happen with services. In a service you get data from the server, you keep them inside and next you deliver some functions that give access and when someone needs these data he just use the injection to take access to the service. Think of this kind of service as something like a singleton class with data, get/set and other methods. A rule is: if you don't know where something is going, more likely is going to the service.(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;
})
Controller: In the images above, you can see easy the controller only get and not give from user interaction. Controllers don't manipulate the Dom. The data here is going from view (user) to the controller by using the scope (or using this
inside the controller) and later manipulate the model using the functions we get by inject the service (model). Many times we make the controller act as a mediator, which break the rule of MVC, by querying the model and passing the result to the view, that is a different pattern name MVP. A rule is: Your controllers must always be as leaner as possible.(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
};
[..]
View: As you can see in the image, model updates the view, not the controller. How? With directives and filters. Be careful, the view have only the presentation of the data (data-binding). Don't contain complex logic. I want to be clear, in MVC the view should access the model directly. Directives and filters deliver this function. If you want to do a DOM manipulation you must use a directive (not a controller). Note: we put the dom manipulation inside the compile and link function of the directive, not in the controller.(FULL CODE1 FULL CODE2)
I have problem with understanding the difference between $scope and model object
Scope is just refer to model as we see up, but is not the model! Scope is used for user interaction too, controller depends on scope and controller depends on model.
so I can manipulate this list in a cached way (keep it local and update it occasionally)?
There are many ways to solve this. Regular we use observer pattern, but in angular there is another way to do this that is better in most of the times. Here an example:
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;
};
}]);
For more information check this, has some amazing answers.
The Problem: You have some remote data. You want all your controllers to have access to it. You don't want them each to get it on their own.
One way to do this in Angular: Use a service. Services are all singletons. This means that your app will only have one instance of the service and can be used to share data. I looked at the link you shared and the below is an example of the second suggestion, "Service is a Model and a Service".
function dataService($http) {
var todos= [];
this.getTodos = function() { return todos; };
this.getToDoList= function() {
// use $http to get remote data and assign it to todos
};
}
Now you can do TodoService.getData() anywhere you've injected it, say maybe your .run block, and from then on, TodoService.getTodos() will return the same data the service got previously.
Alternatively, you can use the service exclusively to get data and not to store (your link's 3rd suggestion). To do that, you would not store var todos
in the service, or have a this.getTodos
, you would only have the getData function (and other data get functions). Then from each controller, you would run TodoService.getData() to run the common http get function.
Where should I store this list after I get it from server and from where it should be set (from controller or from service) so I can manipulate this list in a cached way (keep it local and update it occasionally)?
If you want to store and manipulate it in a cached way, you want to keep your data in the service. Your controllers will get the data from the service. There are a bunch of articles on using services to talk between controllers. They talk about using $broadcast
to send your own events so that an update to one controller will update other independent controllers.
In either case: you do want to bind the todos
list to $scope
in your controller. This will allow you to output its contents in your view and use Angular magic like 2-way binding. In your code:
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;
});
};
}
Then in your view, you can just reference {{todos}}
.
Angular doesn't come with an opinionated way to store data.
Some projects that have addressed this and other related issues:
https://github.com/mgonto/restangular
https://github.com/adrianlee44/ng-backbone
https://github.com/paysavvy/immutable-angular
What I've done in the past is write up a models
and collections
module that stores data. These are just simple constructors.
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;
});
And then in your view model you hook up the view...to the model!
['app.models.User', function Controller(User) {
this.user = new User('bob');
}]
<div>
<button ng-click="vm.user.sayName()">say name</button>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With