-2

I have two tables. One that is working and one that is not working.

My goal is : I want to fix the table that is not working.

The only difference between them is that in the working table the header values are hard coded.

Below is the code :

 <!-- Not working table -->

<table style="margin-left:100px">
    <thead>
        <tr>
            <th style="width:100px;font-weight:bold;cursor:pointer" 
            ng-repeat="value in field_names" ng-click="orderByField='{{value}}'; reverseSort = !reverseSort">
            {{value}}  <span ng-show="orderByField == '{{value}}'">
            <span ng-show="!reverseSort">^</span>
            <span ng-show="reverseSort">v</span>
                    </span>
            </th>
        </tr>           
    </thead>

    <tbody>

    <tr ng-repeat="emp in dataArray|orderBy:orderByField:reverseSort">
        <td>{{emp.a}}</td>
        <td>{{emp.b}}</td>
        <td>{{emp.c}}</td>
    </tr>

    </tbody>

</table>

<!-- working table -->


<table class="table table-bordered">
<thead>
  <tr>
    <th ng-click="orderByField='firstName'; reverseSort = !reverseSort">
      First Name <span ng-show="orderByField == 'firstName'">
      <span ng-show="!reverseSort">^</span>
      <span ng-show="reverseSort">v</span></span>
    </th>
    <th ng-click="orderByField='lastName'; reverseSort = !reverseSort">
        Last Name <span ng-show="orderByField == 'lastName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
    </th>
    <th ng-click="orderByField='age'; reverseSort = !reverseSort">
      Age <span ng-show="orderByField == 'age'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
    </th>
  </tr>
</thead>
<tbody>
  <tr ng-repeat="emp in data.employees|orderBy:orderByField:reverseSort">
    <td>{{emp.firstName}}</td>
    <td>{{emp.lastName}}</td>
    <td>{{emp.age}}</td>
  </tr>
</tbody>

and the javascript is :

$scope.field_names= [];
$scope.table_data={};

$scope.orderByField;

   $scope.dataArray = [{
        a: "Hans",
        b: "Mueller",
        c: "Leipzig"
    }, {
        a: "Dieter",
        b: "Zumpe",
        c: "Berlin"
    }, {
        a: "Bernd",
        b: "Danau",
        c: "Muenchen"

}];

 $scope.data = {
employees: [{
  firstName: 'John',
  lastName: 'Doe',
  age: 30
},{
  firstName: 'Frank',
  lastName: 'Burns',
  age: 54
},{
  firstName: 'Sue',
  lastName: 'Banter',
  age: 21
}]


};

   $scope.reverseSort = false;
function getHeaders(){
    $scope.field_names=Object.keys($scope.dataArray[0]);
    }


getHeaders();
mhodges
  • 10,938
  • 2
  • 28
  • 46
Simon
  • 71
  • 2
  • 10

3 Answers3

0

You do not need to use curly brackets {{}} inside ng-click and ng-show directives.

Its content will be evaluated and the value variable already contains a string.

So just use expressions like

ng-click="orderByField = value"

ng-show="orderByField == value"

And also ng-repeat directive creates its own isolated $scope. So assigning a variable inside the directive creates the variable inside that $scope.

As a solution - add a function in the $scope to assign these fields and then call it on ng-click

or access the variable with $parent object

ng-click="$parent.orderByField = value; $parent.reverseSort = !$parent.reverseSort"
  • using $parent.* here works, but from a maintainability/readability standpoint, it is very frowned upon. See the article on "controller as" that I linked in my answer – mhodges Jun 29 '16 at 19:53
0

You are running into a scoping issue with ng-repeat and orderByField. This is a prime example of why using the "controller as" syntax is recommended by the angularJS team now. Here is a great article to explain

Also note - you do not need the curly braces in ng-click="orderByField = value" and ng-show="orderByField === value"

How this relates to your current code:

You need to put everything on the same scope by using ng-controller="ctrl as name" so that each <th> created by your ng-repeat does not create its own instance of orderByField. The code would look as follows:

WORKING DEMO

HTML

<body ng-app="myApp" ng-controller="myCtrl as Main">
 <!-- Not working table -->
<table style="margin-left:100px">
    <thead>
        <tr>
            <th style="width:100px;font-weight:bold;cursor:pointer" 
                ng-repeat="value in Main.field_names" 
                ng-click="Main.orderByField = value; Main.reverseSort = !Main.reverseSort">
            {{value}}  <span ng-show="Main.orderByField == value">
            <span ng-show="!Main.reverseSort">^</span>
            <span ng-show="Main.reverseSort">v</span>
                    </span>
            </th>
        </tr>           
    </thead>

    <tbody>

    <tr ng-repeat="emp in Main.dataArray|orderBy:Main.orderByField:Main.reverseSort">
        <td>{{emp.a}}</td>
        <td>{{emp.b}}</td>
        <td>{{emp.c}}</td>
    </tr>

    </tbody>

</table>

<!-- working table -->


<table class="table table-bordered">
<thead>
  <tr>
    <th ng-click="Main.orderByField='firstName'; Main.reverseSort = !Main.reverseSort">
      First Name <span ng-show="Main.orderByField == 'firstName'">
      <span ng-show="!Main.reverseSort">^</span>
      <span ng-show="Main.reverseSort">v</span></span>
    </th>
    <th ng-click="Main.orderByField='lastName'; Main.reverseSort = !Main.reverseSort">
        Last Name <span ng-show="Main.orderByField == 'lastName'"><span ng-show="!Main.reverseSort">^</span><span ng-show="Main.reverseSort">v</span></span>
    </th>
    <th ng-click="Main.orderByField='age'; Main.reverseSort = !Main.reverseSort">
      Age <span ng-show="Main.orderByField == 'age'"><span ng-show="!Main.reverseSort">^</span><span ng-show="Main.reverseSort">v</span></span>
    </th>
  </tr>
</thead>
<tbody>
  <tr ng-repeat="emp in Main.data.employees|orderBy:Main.orderByField:Main.reverseSort">
    <td>{{emp.firstName}}</td>
    <td>{{emp.lastName}}</td>
    <td>{{emp.age}}</td>
  </tr>
</tbody>
</body>

Javascript

var app = angular.module("myApp", [])
.controller("myCtrl", function ($scope) {
  var $this = this;
  $this.field_names= [];
  $this.table_data={};

  $this.orderByField = "";

  $this.dataArray = [
     {
        a: "Hans",
        b: "Mueller",
        c: "Leipzig"
     }, 
     {
        a: "Dieter",
        b: "Zumpe",
        c: "Berlin"
     }, 
     {
        a: "Bernd",
        b: "Danau",
        c: "Muenchen"
     }
];

$this.data = {
employees: [{
  firstName: 'John',
  lastName: 'Doe',
  age: 30
},{
  firstName: 'Frank',
  lastName: 'Burns',
  age: 54
},{
  firstName: 'Sue',
  lastName: 'Banter',
  age: 21
}]


};

$this.reverseSort = false;
function getHeaders(){
  $this.field_names=Object.keys($this.dataArray[0]);
}


getHeaders();
});
Community
  • 1
  • 1
mhodges
  • 10,938
  • 2
  • 28
  • 46
  • Ok so for some reason this is working...but there are three things here that i don't understand...why did you changed everything to global using var $this = this...secondly if you wanted to change to global can't you do like : this.orderByField instead of $this.orderByField.....finally where did the variable "Main" came from ? since y,re using Main.orderByField and Main.reverseSort....etc. – Simon Jun 29 '16 at 23:15
  • @Simon If you read the article I linked, you will understand how/why this is working, and where "Main" came from. As for using "var $this = this", that is a convention that I use because "this" is ambiguous depending on scope. Once you enter any iterative function (foreach, map, filter, etc.), ajax callback, and many others, "this" becomes scoped to the local function and you lose the reference to the top-level "this" unless you save it off into a variable. using "$this = this" gives you a consistent explicitly clear and unambiguous reference to the top-level "this". – mhodges Jun 30 '16 at 15:16
0

You might create a function in your Controller and call it passing value as parameter.

Example:

$scope.changeSort = function(val) {
  $scope.orderByField = val;
  $scope.reverseSort = !$scope.reverseSort;
}

And in your HTML:

<th style="width:100px;font-weight:bold;cursor:pointer" 
    ng-repeat="value in field_names" ng-click="changeSort(value);">
    {{value}}  <span ng-show="orderByField == '{{value}}'">
        <span ng-show="!reverseSort">^</span>
        <span ng-show="reverseSort">v</span>
    </span>
</th>

UPDATE:

I wrote a plunker to show what I suggested, including the up and down arrows.

http://plnkr.co/W2vElBasnmRzYie2sZE1

  • Thanks...your code worked perfectly !!!! I wonder why is it necessary to create a function here and why {{value}} was not working....because when i inspected element in chrome the HTML of the working and the not working table were the same... anyway thanks...your code worked and therefore you are awesome !!! – Simon Jun 29 '16 at 23:00
  • It's because the code had already been compiled by angular before the value been wrote. – Waldir J. Pereira Junior Jun 29 '16 at 23:08
  • Wow...i wonder what that means...do you have a link where i can study and understand the flow of angular..e.g when does the compiler gets called and when does the values gets processed.... – Simon Jun 29 '16 at 23:11
  • You should take a look at compiler service page: https://docs.angularjs.org/guide/compiler Remember to mark the answer as valid to help other users. – Waldir J. Pereira Junior Jun 29 '16 at 23:17
  • You need a 15 reputation to your vote get public. But I'm not sure, but I think you as the question owner can mark the answer as correct. Not sure.. I'm new here. :) Thks – Waldir J. Pereira Junior Jun 29 '16 at 23:49