Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to keep model in angularJS app?

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?

like image 608
1110 Avatar asked Apr 30 '16 14:04

1110


People also ask

What is model in AngularJS?

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.

Which method is used to create models in AngularJS?

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.

In which folder are the most important files stored in AngularJS?

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.


3 Answers

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. enter image description here

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.

like image 110
Thomas Karachristos Avatar answered Sep 22 '22 20:09

Thomas Karachristos


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

like image 40
C.C. Avatar answered Sep 20 '22 20:09

C.C.


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>
like image 39
Daniel Lizik Avatar answered Sep 23 '22 20:09

Daniel Lizik