0

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?

1
  • What you need is a service. AngularJS services are singletons, your fetched data will be accessible in the controllers if you inject the service. Commented Jun 21, 2015 at 20:53

2 Answers 2

2

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;
        });
    });
Sign up to request clarification or add additional context in comments.

2 Comments

Could you provide an example with html to show the data from the get function? I'm getting only a blank space, not the actual data. Also, there is no errors in my console.
hava a look here: plnkr.co/edit/WBJKwmAKKhAj30FQbfGj?p=preview . It doesn't use $http, but has a service that returns a promise with $timeout. There should be no difference between calling $http in controller and in service
0

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

4 Comments

But with this method i'll still need to call the controller each place i want to show the data, right? Is there a way to make it more simple? Specially because angularjs 2.0 will have no ng-controller, so if there is already a work around, that would be better
You have to define the controller only once - not multiple times! Not sure about angular 2.0.
Ok. I'll try to work with what you said. Note: About the controller stuff, i saw it in here: youtube.com/watch?v=gNmWybAyBHI in case you want to check it.
Interesting, it seems in Angular 2.0 the conrollers will be replaced by directives, which makes sense as directives are more powerful than only controllers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.