1

Here is my flow: The main page is at '/main' url, so when the user goes to that page, my web server returns a static html:

<!DOCTYPE html>
<html ng-app="sam">
    <head>
        <link rel="stylesheet" type="text/css" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
    </head>
    <body>
        <div ng-controller="BuildingsController as buildings">  
            <button ng-click="RefreshBuildings()">Refresh</button>
            <h1>{{buildings.elements.length}}</h1>
            <table>
                <tr>
                <th>id</th>
                <th>name</th>
                <th>last_updated</th>
                <th>based_on_file</th>
                </tr>
                <tr ng-repeat="element in buildings.elements | orderBy:'-id'">              
                    <td>{{element.id}}</td>
                    <td><a ng-href="/getTenants?buildingId={{element.id}}">{{element.name}}</a></td>
                    <td>{{element.last_updated | date}}</td>
                    <td>{{element.based_on_file}}</td>
                    <td><button ng-click="buildings.UpdateDataBase(element.id)">Refresh</button></td>
                </tr>
            </table>
        </div>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.13/angular.min.js"></script>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
        <script type="text/javascript" src="app.js"></script>
    </body>
</html>

Here is the js file:

(function(){
    var app = angular.module('sam', []);
    app.controller('BuildingsController', ['$http','$log', function($http, $log){

        //Update scope pramaters
        this.RefreshGui = function(elements){
            this.elements = elements
        };

        //call server to get all builgings' info
        this.GetBuildingsData = function(){         
            //'this' inside the scope of success function will point to $http, so we store the controller pointer into tmp
            tmp = this;
            $http.get('/fetchBuildings').success(function(data) {
                //$log.log(data);
                tmp.RefreshGui(data);               
            });
        };

        //call server to update building's database
        this.UpdateDataBase = function(element_id){ 
            //'this' inside the scope of success function will point to $http, so we store the controller pointer into tmp
            tmp = this;

            //need to serialize data in angular (http://stackoverflow.com/questions/12190166/angularjs-any-way-for-http-post-to-send-request-parameters-instead-of-json)
            //as a best practice do it also when sending ajax requests via jquery

            // or To globally override the default transforms, override the $httpProvider.defaults.transformRequest and $httpProvider.defaults.transformResponse properties of the $httpProvider. as suggested in http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/
            $http.post('/updateBuildings', $.param({'element_id': element_id})).success(function(data) {
                //$log.log(data);
                tmp.RefreshGui(data);               
            });
        };


        //on launch call UpdateBuildings with no paramters, this will build the database from scratch
        this.GetBuildingsData();

    }]);    
})();

I'm having a hard time understanding how to continue the flow when the user clicks on the link of the building name :

<td><a ng-href="/getTenants?buildingId={{element.id}}">{{element.name}}</a></td>

My intention is that the user will be presented with a new html page where he can see a table of tenants' data from the relevant building. I have no problem at the server side getting the building id and fetch those details from the database but the question is what do I return to the client? A static html ? how do I plant the dynamic details I've just fetched from the database in that html using angular? Is that a bad design in the first place? cause I think it is not consistent with angular's single page application basics.

Please help. Thanks!

omer bach
  • 2,345
  • 5
  • 30
  • 46

1 Answers1

5

You are having the normal conceptual difficulties when transitioning from server side rendering to the Singe-Page-Application (SPA) client side rendering world. I'll try to summarize the basics to get you started:

  • In a SPA, you have a unique static index.html file, which gets loaded at the first request and it's never reloaded again. It's the only file that defines the html and body tags, includes the required script and css files and usually creates the common structure of your webpage: header, footer, menu...

  • The rest of your html files of your app are called "partials". They are static pieces of html, without the html and body tags, which get inserted in the index.html file. To define where they get inserted, you have to use a client-side routing system. Take a look at ngRoute or ui-router (I recommend this one). They allow you to define blocks (ngViews or ui-views) in your index.html that will get filled with your partials.

  • Apart from the static html, you need the dynamic data that will fill your views (your tenants, your buildings...). You will get this data via AJAX requests, usually using the angular $http service or the $resource if you have an REST API in your backend. These request will NOT return Html, instead, they will return JSON objects which you will assign to your scope, and this will automatically update the binding that you have defined in your views.

Basically, and simplifying: the index.html is loaded, a partial is loaded into it and the controller associated with this partial makes and AJAX call to get the data in JSON format that will fill this partial.

EDIT

With the ui-router, to give you an idea, you would do something like this:

First you define the building state:

.config(function ($stateProvider) {

        $stateProvider.state('building', {

            url : "/building/:id",
            views: {
            "main": {
                controller: 'BuildingController',
                templateUrl: 'partials/building.tpl.html'
            }
        },
        resolve : {

            building : function($stateParams, $http) { //get the building via AJAX, $stateParams.id is the id of your building 

                return $http('/api/building/:id', {id: $stateParams.id}).success(function(res){

                    return res;
                });
            }
        }
    });
 });

This would load the building.tpl.html partial to the ui-view "main" which you have to define in your index.html. Note that we are using the resolve property to get the building data from the backend. Once the partial is loaded, the controller will be executed, and the building info will be injected so you can assign it to the scope:

.controller('BuildingController', function($scope, building){

    $scope.building = building;
});

So now, your links would be like this:

<td><a ui-sref="building({id: element.id})">{{element.name}}</a></td>

I really suggest that you take a look at the ui-router documentation:

https://github.com/angular-ui/ui-router/wiki

cuttlas
  • 971
  • 5
  • 17
  • 1
    Thanks, so following this approach with my needs, lets say I return a "partial" upon clicking the link. how can I pass the building id to this partial, so the controller,upon launch, will send it to the server? – omer bach Jun 30 '14 at 12:35