celsomtrindade
celsomtrindade

Reputation: 4671

AngularJS reuse multiple controllers to build a webapp

What I'm looking for is to learn a proper way to build a webapp. I already built some things, but I've got to a point where I need to reuse some data and with ng-controllers, it's getting harder.

I already know controllers are not the best option, so I tried to jump to directives, based on some articles I've read. But none of them has helped me.

So, let me try to describe it.

Description

I'm building a dashboard, where i have some clients (add/edit/del), projects (which invole one or more clients), agenda, configuration, financials, etc..

I've built a lot of things already, but for example:

On the home page I'm displaying a table with the last 5 clients added to the app, also a table with the last 5 projects added to the app. Then, on the clients.html page, I display the whole table, same goes for projects, on the project.html. Both with just 3-4 fields with name, tel and email. Then on the individual client page, i display the whole information about that client. Such as address, email, contacts, observations, etc. And also a list of projects he is involved.

So what I have is something like this:

app.js

myApp.controller('ClientesCtrl', function ($scope, $http, $routeParams) {
    $scope.pagename = "Clientes";

    $scope.get_cliente = function() { //Function - Get Cliente
        $http.get("scripts/data/clientes.json")
        .success( function(data) {
            $scope.pagedClientes = data;
        })
        .error(function(data) {});
    };

    $scope.add_cliente = function() { //Function - Add Cliente
        $scope.formprevent = true;
        $http.post('scripts/php/db.php?action=add_cliente',
            {
                'cod': $scope.cad.cod,
                [... more data ...]
            }
        )
        .success(function (data, status, headers, config) {})
        .error(function (data, status, headers, config) {});
    };
});

Same goes for projects, each one with it's controller.

My folder/File organizations is very very simple (since I don't know what I can put in different files, or even how to call it back). It's something like this:

-index.html
-scripts
--js
---angular.min.js
---angular-route.min.js
--app
---app.js
-content
--home.html
--clients.html
--projects.html

The Problem

The problem starts when i need to show those data in a lot of pages.
For example in the home page, i have a list with a resume of the main data, such as total clients, total projects, and it's like this:

<div class="col-md-3" ng-controller="ClientesCtrl">
    <div ng-init="get_cliente();>
        <div class="label">{{pagedClientes.length || "00"}}</div>
        <div class="text">clientes totais</div>
    </div>
</div>
<div class="col-md-3" ng-controller="ProjectsCtrl">
    <div ng-init="get_projects()">
        <div class="label">{{pagedProjects.length || "00"}}</div>
        <div class="text">Processos totais</div>
    </div>
</div>
<div class="col-md-3">
    <div>
        <div class="label">00</div>
        <div class="text">Processos abertos</div>
    </div>
</div>
<div class="col-md-3">
    <div>
        <div class="label">00</div>
        <div class="text">Compromissos abertos</div>
    </div>
</div>

<div class="table-body" ng-controller="ClientesCtrl">
    <table ng-init="get_clients()">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Options</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="client in pagedClients | limitTo:-5 | orderBy:'-id'" ng-if="pagedClients.length > 0">
                <td>{{cliente.cod}}</td>
                <td>{{cliente.nm_client}}</td>
                <td>
                    <a class="bt-t bt-inf" href="#/detcliente/{{cliente.id}}"></a>
                </td>
            </tr>
            <tr ng-if="pagedClientes.length == 0">
                <td colspan="3"><h3>No client</h3></td>
            </tr>
        </tbody>
    </table>
</div>

<div class="table-body" ng-controller="ProjectsCtrl">
    <table ng-init="get_projects()">
        <thead>
            <tr>
                <th>ID</th>
                <th>Project</th>
                <th>Options</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="project in pagedProjects | limitTo:-5 | orderBy:'-id'" ng-if="pagedProjects.length > 0">
                <td>{{project.cod}}</td>
                <td>{{project.nm_cliente}}</td>
                <td>
                    <a class="bt-t bt-inf" href="#/detproject/{{project.id}}"></a>
                </td>
            </tr>
            <tr ng-if="pagedClientes.length == 0">
                <td colspan="3"><h3>No project</h3></td>
            </tr>
        </tbody>
    </table>
</div>

So, basically, I need to add the controller in each block I need to display that data, also I have to 'init' the function to get the data again. This is a simple example, but I think it was enough to show what I need to solve.

It's worse when I need to show the individual client, with only their projects. So before I get crazy with all of those controllers, I want to know how is the best way to put up the logic, the folder/file organization, the code organization. Is it better to use a directive? to make the directive call a controller? Call multiple controllers? Or what?

Upvotes: 0

Views: 91

Answers (2)

Ana F
Ana F

Reputation: 641

You need to use services to fetch the data: https://docs.angularjs.org/guide/services. For your code it would look something like this:

    app.factory('clients', function ($http) {

        var getClients = function() { //Function - Get Cliente
            return $http.get("scripts/data/clientes.json")
            .success( function(data) {
                return data;
            })
            .error(function(data) {});
        };

        var add_cliente = function(cad) { //Function - Add Cliente
            $http.post('scripts/php/db.php?action=add_cliente',
                {
                    'cod': cad.cod,
                    [... more data ...]
                }
            )
            .success(function (data, status, headers, config) {})
            .error(function (data, status, headers, config) {});
        };

        return {
            getClients: getClients,
            add_cliente: add_cliente
        }

}) 

You can then inject the service in a controller and use the functions in your controller:

    app.controller('Ctrl', function (clients, $scope) {
        clients.getClients().then(function (data) {
        $scope.myClients = data;
        });
    });

Upvotes: 2

Michael
Michael

Reputation: 3104

Read the client data on initialization of the controller - not need to use a ng-init.

myApp.controller('ClientesCtrl', function ($scope, $http, $routeParams) {
    $scope.pagename = "Clientes";

    $http.get("scripts/data/clientes.json")
        .success( function(data) {
            $scope.pagedClientes = data;
        })
        .error(function(data) {});

    $scope.add_cliente = function() { //Function - Add Cliente
        $scope.formprevent = true;
        $http.post('scripts/php/db.php?action=add_cliente',
            {
                'cod': $scope.cad.cod,
                [... more data ...]
            }
        )
        .success(function (data, status, headers, config) {})
        .error(function (data, status, headers, config) {});
    };
});

Controllers can be nested. Define the controller on a div which wraps the area where you need the client data. Same for the ProjectsController. You could even merge the 2 controllers in one.

<div ng-controller="ClientesCtrl">
    <div class="col-md-3" >
        <div ng-init="get_cliente();>
            <div class="label">{{pagedClientes.length || "00"}}</div>
            <div class="text">clientes totais</div>
        </div>
    </div>
    ....

Upvotes: 0

Related Questions