title: Angular ui-router's ui-sref created dynamically in a directive?
body: <p>I am working on a line of business application that is using Angular to create a SPA around a Node.js api server. I decided on using ui-router cause of the state-machine and their intuitive way of embedding urls but I chanced upon a slight challenge when creating dynamic URLs within a directive.</p>
  
  <p>I am using jQuery Datatables for my data grid as a directive but any action links generated using 'fnRender' don't seem to compile the 'ui-sref' to their respective 'href'links. The directive code is as follows:</p>
  
  <pre><code>app.directive('datatable', function ($http) {
    return {
      restrict: 'A',
      link: function ($scope, $elem, attrs) {
          var responsiveHelper;
          var breakpointDefinition = {
              tablet: 1024,
              phone : 480
          };
          var options = {
              bDeferRender: true,
              sPaginationType: "full_numbers",
              oLanguage: {
                  sEmptyTable: "No records returned",
                  sSearch: "&lt;span&gt;Search:&lt;/span&gt; ",
                  sInfo: "Showing &lt;span&gt;_START_&lt;/span&gt; to &lt;span&gt;_END_&lt;/span&gt; of &lt;span&gt;_TOTAL_&lt;/span&gt; entries",
                  sLengthMenu: "_MENU_ &lt;span&gt;entries per page&lt;/span&gt;",
                  sProcessing: "Loading..."
              },
              sDom: "lfrtip",
              oColVis: {
                  buttonText: "Change columns &lt;i class='icon-angle-down'&gt;&lt;/i&gt;"
              },
              oTableTools: {
                  sSwfPath: "js/plugins/datatable/swf/copy_csv_xls_pdf.swf"
              },
              bAutoWidth     : false,
              fnPreDrawCallback: function () {
                  if (!responsiveHelper) {
                      responsiveHelper = new ResponsiveDatatablesHelper($elem, breakpointDefinition);
                  }
              },
              fnRowCallback  : function (nRow, aData, iDisplayIndex, iDisplayIndexFull) {
                  responsiveHelper.createExpandIcon(nRow);
              },
              fnDrawCallback : function (oSettings) {
                  responsiveHelper.respond();
              }
          };
          if (typeof $scope.dtOptions !== 'undefined') {
              angular.extend(options, $scope.dtOptions);
          }
          if (attrs['dtoptions'] === undefined) {
              for (property in attrs) {
                  switch (property) {
                      case 'sajaxsource':
                          options['sAjaxSource'] = attrs[property];
                      break;
                      case 'sajaxdataprop':
                          options['sAjaxDataProp'] = attrs[property];
                      break;
                  }
              }
          } else {
              angular.extend(options, $scope[attrs['dtoptions']]);
          }   
  
          if (typeof options['sAjaxSource'] === 'undefined') {
              throw "Ajax Source not defined! Use sajaxsource='/api/v1/*'";
          }
          if (typeof options['fnServerData'] === 'undefined') {
              options['fnServerData'] = function (sSource, aoData, resultCb) {
                  $http.get(sSource, aoData).then(function (result) {
                      resultCb(result.data);
                  });
              };
          }
          options.aoColumnDefs = [];
          $elem.find('thead th').each(function() {
              var colattr = angular.element(this).data();
              if (colattr.mdata) {
                  if (colattr.mdata.indexOf("()") &gt; 1) {
                      var fn = $scope[colattr.mdata.substring(0, colattr.mdata.length - 2)];
                      if (typeof fn === 'function') {
                          options.aoColumnDefs.push({
                              mData: fn,
                              sClass: colattr.sclass,
                              aTargets: [colattr.atargets]
                          });     
                      } else {
                          throw "mData function does not exist in $scope.";
                      }
                  } else {
                      options.aoColumnDefs.push({
                          mData: colattr.mdata,
                          sClass: colattr.sclass,
                          bVisible: colattr.bvisible,
                          aTargets: [colattr.atargets]
                      }); 
                  }
              } else {
                  if (colattr.fnrender.indexOf("()") &gt; 1) {
                      var fn = $scope[colattr.fnrender.substring(0, colattr.fnrender.length - 2)];
                      if (typeof fn === 'function') {
                          options.aoColumnDefs.push({
                              fnRender: fn,
                              sClass: colattr.sclass,
                              aTargets: [colattr.atargets]
                          });     
                      } else {
                          throw "fnRender function does not exist in $scope.";
                      }
                  } else {
                      options.aoColumnDefs.push({
                          fnRender: function (oObj) {
                              return "&lt;a tooltip class='btn' title='View' ui-sref=\""+colattr.tag+".show({slug:\'"+oObj.aData._id+"\'})\"&gt;&lt;center class=\"icon-search\"&gt;&lt;/center&gt;&lt;/a&gt;";
                          },
                          sClass: colattr.sclass,
                          bVisible: colattr.bvisible,
                          aTargets: [colattr.atargets]
                      }); 
                  }
              }
          });
          $elem.dataTable(options);
          $(".dataTables_length select").wrap("&lt;div class='input-mini'&gt;&lt;/div&gt;").chosen({disable_search_threshold: 9999999 });
      }
    }
  });
  </code></pre>
  
  <p>It runs with out complications and even generates the following anchor tag:</p>
  
  <pre><code>&lt;a ui-sref="organisation.show({slug:'527a44c02aa9ce3a1c3fbc17'})"&gt;&lt;/a&gt; 
  </code></pre>
  
  <p>However, ui-router doesn't compile it to a respective state url. What could be the issue? Is there some configuration I may have missed?</p>
  
  <p>Thanks</p>