<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <script data-require="angularjs@1.5.0" data-semver="1.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.2/angular.js"></script>
    <script data-require="jquery@1.9.1" data-semver="1.9.1" src="https://code.jquery.com/jquery-1.9.1.js"></script>
    <script src="angular-responsive-table.min.js"></script>

    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="angular-responsive-table.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="TableController">
    <table wt-responsive-table>
      <thead>
          <tr>
              <th ng-repeat="column in columnNames">{{column}}</th>
          </tr>
      </thead>
      <tbody ng-show="itemList && itemList.length > 0">
          <tr ng-repeat="item in itemList">
              <td ng-repeat="attribute in attributeNames">{{item[attribute]}}</td>
          </tr>
      </tbody>
  </table>
  </body>

</html>
// Code goes here
  angular.module('myApp',['wt.responsive'])
  
  .controller('TableController', ['$scope', function($scope){
    $scope.itemList = [
      {
        firstname: 'test11',
        lastname: 'test12'
      },
      {
        firstname: 'test21',
        lastname: 'test22'
      }
    ];
    
    $scope.attributeNames = ['firstname','lastname'];
    
    $scope.columnNames = ['First Name','Last Name'];
  }]);

// https://github.com/awerlang/angular-responsive-tables
!function(){"use strict";function getHeaders(element){return element.querySelectorAll("tr > th")}function updateTitle(td,th){var title=th&&th.textContent;!title||!td.getAttributeNode("data-title-override")&&td.getAttributeNode("data-title")||(td.setAttribute("data-title",title),td.setAttribute("data-title-override",title))}function colspan(td){var colspan=td.getAttributeNode("colspan");return colspan?parseInt(colspan.value):1}function wtResponsiveTable(){return{restrict:"A",controller:function($element){return{getHeader:function(td){var firstHeader=td.parentElement.querySelector("th");if(firstHeader)return firstHeader;var headers=getHeaders($element[0]);if(headers.length){var row=td.parentElement,headerIndex=0,found=Array.prototype.some.call(row.querySelectorAll("td"),function(value,index){return value===td?!0:void(headerIndex+=colspan(value))});return found?headers.item(headerIndex):null}}}},compile:function(element,attrs){attrs.$addClass("responsive");var headers=getHeaders(element[0]);if(headers.length){var rows=element[0].querySelectorAll("tbody > tr");Array.prototype.forEach.call(rows,function(row){var headerIndex=0;Array.prototype.forEach.call(row.querySelectorAll("td"),function(value,index){var th=value.parentElement.querySelector("th")||headers.item(headerIndex);updateTitle(value,th),headerIndex+=colspan(value)})})}}}}function wtResponsiveDynamic(){return{restrict:"E",require:"^^wtResponsiveTable",link:function(scope,element,attrs,tableCtrl){setTimeout(function(){Array.prototype.forEach.call(element[0].parentElement.querySelectorAll("td"),function(td){var th=tableCtrl.getHeader(td);updateTitle(td,th)})},0)}}}angular.module("wt.responsive",[]).directive("wtResponsiveTable",[wtResponsiveTable]).directive("td",[wtResponsiveDynamic])}();
/* original: http://css-tricks.com/responsive-data-tables/ */

.responsive {
    width: 100%;
    border-collapse: collapse;
}

@media only screen and (max-width: 800px) {

    /* Force table to not be like tables anymore */
    /* table.responsive,*/
    .responsive thead,
    .responsive tbody,
    .responsive tr,
    .responsive th {
        display: block;
    }

    /* Hide table headers (but not display: none;, for accessibility) */
    .responsive thead tr, .responsive th {
        position: absolute;
        top: -9999px;
        left: -9999px;
    }

    .responsive tr {
        border: 1px solid #ccc;
    }

    .responsive td:nth-child(odd), .responsive td:nth-child(even) {
        /* Behave  like a "row" */
        border: none;
        border-bottom: 1px solid #eee;
        position: relative;
        padding-left: 50%;
        white-space: normal;
        text-align: left;

        display: block;
        -webkit-box-sizing: content-box;
           -moz-box-sizing: content-box;
                box-sizing: content-box;
        min-height: 1em;
    }

    .responsive td:nth-child(odd)::before, .responsive td:nth-child(even)::before {
        /* Now like a table header */
        position: absolute;
        /* Top/left values mimic padding */
        left: 6px;
        width: 45%;
        padding-right: 10px;
        -ms-word-wrap: break-word;
            word-wrap: break-word;
        text-align: left;
        font-weight: bold;
        /*
        Label the data
        */
        content: attr(data-title);
    }
    
    .responsive td.responsive-omit-title:nth-child(odd), .responsive td.responsive-omit-title:nth-child(even) {
        padding-left: 6px;
    }

    .responsive td.responsive-omit-title::before {
        display: none;
    }

    .responsive td.responsive-omit-if-empty:empty {
        display: none;
    }
}
<table wt-responsive-table>
    <thead>
        <tr>
            <th ng-repeat="column in columnNames">{{column}}</th>
        </tr>
    </thead>
    <tbody ng-show="itemList && itemList.length > 0">
        <tr ng-repeat="item in itemList">
            <td ng-repeat="attribute in attributeNames">{{item[attribute]}}</td>
        </tr>
    </tbody>
</table>