Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Yesterday I start learning AngularJs online. I decided to create some useful stuffs for my new project using Angular. Below is some portion of my hard work :

The HTML Part

<div data-ng-controller="DataGrid_Controller">
    <table class="table table-stripped">
        <thead>
            <tr>
                <th data-field="fname"> First Name </th>
                <th data-field="lname"> Last Name </th>
                <th data-field="email"> Email </th>
            </tr>
        </thead>
        <tbody>

        </tbody>
    </table>
</div>

The Angular Part

<script type="text/javascript">
var app = angular.module('TestApp',[]);

app.controller('DataGrid_Controller', function($scope){
    //var fields = ['fname', 'lname', 'email']; 
    //How can I get the value of data-field attributes in my 'Controller' so that I could use them 
})
</script>

How can I get the value of data-attributes from child elements (I don't know either the term element exists or not in angular?) in my controller.

I am 1 day old baby for AngularJs so please show me the right way if you think I am catching the wrong way of doing it. I have used jQuery for years so I am thinking a controller as plugin. Please help me solving the problem.

share|improve this question
 
It looks like you're doing it backwards. The template should display value from the data stored in the scope. You're trying to get data from the template. controllers shouldn't deal with HTML elements. If you told us what you want to achieve, at a higher level, it would be easier to help. –  JB Nizet Nov 17 '13 at 10:51
 
@JBNizet I want to create 'plugin' which gets the values from the database and displays it in html table. The user (for now me) should be able to specify which fields to retrieve from database table within the markup (you called it template). –  Lekhnath Nov 17 '13 at 10:59
 
By "the user", I assume you mean "the developer". The controller scope should contain an array of JavaScript objects, and the markup should use {{ user.firstName }}(for example) to display the user first name. –  JB Nizet Nov 17 '13 at 11:06
 
@JBNizet If I specified the fields within the controller it self, then how can I reuse that controller for making other datagrids? An example code will be helpful because I am not going to understand until I get it working. Sorry for my childish behavior. –  Lekhnath Nov 17 '13 at 11:15
 
If you want to use controller in other datagrids, then what logic that controleer should realize? –  Alexei Nov 17 '13 at 11:32
show 1 more comment

1 Answer

up vote 1 down vote accepted

In Angular, you need to think in terms of model, not the resulted DOM. The model is the only source of truth. So, you need to put your headers somewhere in your model. Then you make a loop through you data, and for each item you iterate over headers and create a table. You'll need a directive to work woth DOM, a controller to contain the data and a simple template:

The DOM:

<div data-ng-controller="DataGrid">
  <table class="table table-striped">
    <thead>
      <tr>
        <th data-header="firstName" data-headers="headers">
          First name
        </th>
        <th data-header="lastName" data-headers="headers">
          Last name
        </th>
      </tr>
    </thead>
    <tbody>
      <tr data-ng-repeat="character in characters">
        <td data-ng-repeat="header in headers">
          {{character[header]}}
        </td>
      </tr>
    </tbody>
  </table>
</div>

Angular application:

'use strict';

var DataAttributes = angular.module('DataAttributes', []);

Datagrid controller:

'use strict';

DataAttributes.controller('DataGrid', ['$scope', function($scope){
    // let this data came from server
    $scope.characters = [
        {
            'firstName' : 'Anakin',
            'lastName' : 'Skywalker',
            'email' : '[email protected]',
            'age' : 9
        },
        {
            'firstName' : 'Kos',
            'lastName' : 'Palpatine',
            'email' : '[email protected]',
            'age' : 60
        },
        {
            'firstName' : 'Jar',
            'lastName' : 'Jar',
            'email' : '[email protected]',
            'age' : 23
        }
    ];

    $scope.headers = [];
}]);

And a directive:

'use strict';

DataAttributes.directive('header', [function(){
    return {
        'restrict' : 'A',
        'scope' : {
            'headers' : '='
        },
        'link' : function(scope, iElement, iAttrs){
            scope.headers.push(iAttrs['header']);
        }
    };
}]);

I've created a plunkr, so you can play with it.

Let's see what is under the hood. Suppose you've already got your data (characters) somewhere else. Now you want to dynamically build a table with some fields from it. You create a directive to capture field name (header). It need to put header names in the controllers's scope. So, you need to bind a model from parent scope, to directive's. This is achieved with 'headers' : '=' line, which tells Angular to

set up bi-directional binding between a local scope property and the parent scope property of name defined via the value of the attr attribute. If no attr name is specified then the attribute name is assumed to be the same as the local name.

The directive simply pushes field names to parent scope. Now, ngRepeat can be used to iterate through them and render a row for each element from characters. That's it!

share|improve this answer
1  
Before reading your answers I learned Angular JS books thoroughly and now I am able to understand your code. This is really a fine way to solve my problem. Thank you for your plunkr also. –  Lekhnath Nov 22 '13 at 8:39
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.