user348173
user348173

Reputation: 9278

Properly work with data in angular

I am trying to understand how to properly work with data in Angular 1.

I am using component based approach. Let's consider a simple case. I have side navigation and dashboard. I need to show departments data in these components.

import sidenavHtml from './sidenavigation.html';
import sideNavController from './sidenavigation.controller';

export default SideNavigation;

SideNavigation.$inject = [
];

function Sidenav() {
    return {
        restrict: 'E',
        scope: {},
        template: sidenavHtml,
        controller: sideNavController,
        controllerAs: 'ctrl',
        link: function ($scope, elem, attrs) {

        }
    };
}

export default class SideNavigationController {
    ...

    $onInit() {
        this.getDepartments();
    }

    getDepartments() {
        this.departmentService.getDepartments().then((result) => {
            this.departments= result.data;
        });
    }
}

export default class DashboardController {
    ...

    $onInit() {
        this.getDepartments();  
    }

    getDepartments() {

        this.departmentService.getDepartments().then((result) => {
            this.departments= result.data;              
        });
    }
}

export default Departments;  

function Departments($http) {

    function getDepartments() {
        return $http({url: 'http://localhost:9000/api/departments', method: 'GET'});
    }

     function create(newDepartment) {
        return $http.post('http://localhost:9000/api/departments', newDepartment);
    }

    return {getDepartments, create};
}

In the Dashboard component user can create new department (creating is another component which is called from Dashboard component). When user created new department I need to notify SideNavigation and Dashboard about it. So, in the Dashboard and SideNavigation components I use the following code: this.$rootScope.$on('updateDepartmens', ()=> { this.getDepartments(); });

Well, disadvantages of this aproach are obvious. When my app is render I get two http requests and I use $rootScope. I have decided to rewrite service in the following way:

export default Departments;  

    function Departments($http) {
        this.departments;

        function getDepartments() {
           if(!departments) {
             $http({url: 'http://localhost:9000/api/departments', method: 'GET'})
             .then((response) => {                   
                this.departments = response.data;                    
             })
             .catch((err) => {
                console.log('error');   
             });
           }

           return this.departments; 
        }

         function create(newDepartment) {
            $http.post('http://localhost:9000/api/departments', newDepartment)
            .then((response) => {
               // handle response and add to departments;
               ...
               this.departments.push(response.data);
            );
    }  

        return {getDepartments, create};
    }

How do you think is it good approach or there is another way?

How do you think should I use this approach overall or use my first approach(call service method which make http request) when I don't need sharing data and use second approach(bind to variable) when I need sharing data?

One additional question. Do you use mapping server models to client models or just use objects returned from server ?

Upvotes: 1

Views: 52

Answers (1)

AndreaM16
AndreaM16

Reputation: 3985

How do you think is it good approach or there is another way?

I think your second approach is correct but, if you want to intercept a certain event, for instance, reload data when it gets fetched, you don't want to auto-execute a particular function bound to that event every time.

I had a similar problem recently, I needed to execute a function only when data was fetched by a factory. I hate using $rootScope for such things. I don't like using it because it makes the application messy and I also noticed side-effects on application's benchmarks. But as you know, using $rootScope events like $broadcast and $on is really a good thing.

I found out a better way to realize such thing. Using Postal.js you can create virtual buses on your application that are shared between the components you want. For instance, you can subscribe to a channel reloadItems with both DataFactory and DataController and you'll emit, only on that channel, that you fetched the items and intercept that message on your controller and execute the function bound to that event. After that, if you wish, you can unsubscribe from that channel and free that bus. You can share a particular bus with n different modules.

I noticed that using this library increases overall speed of my application since I'm not attaching anything to $rootScope.

That's an example of usage

// . . . Cool stuff
//Factory
$scope.$bus.publish({
                  channel : 'reloadItems',
                  topic   : 'reloadItems'
                  data    : items
);

// . . . Cool Stuff also
//Controller
$scope.$bus.subscribe({
  channel  : 'reloadItems',
  topic    : 'reloadItems',
  callback : function () {
    reloadItems();
  }
});

I really suggest you to give it a shot. You can find a interesting article on how to use it with Angular here.

How do you think should I use this approach overall or use my first approach(call service method which make http request) when I don't need sharing data and use second approach(bind to variable) when I need sharing data?

I feel like you should not bind these things to a variable. Just use events to manage that. And, as I said before, your second approach is better and more modular.

Do you use mapping server models to client models or just use objects returned from server ?

Personally, I just use objects returned from the server. I like having a slim front-end and I make the most of parsing of data in the back-end, but, if I somehow need to work with data in the front-end, I never do it in controllers, I do that in Factories or Services.

I hope I have been helpful.

Upvotes: 1

Related Questions