How to get angular ui-router's ui-sref to work, when inside a directive's template?

All we need is an easy explanation of the problem, so here it is.

Basically, I am trying to change/customize the behaviour of the ui.bootstrap.accordion. All is working, except for integration with ui-router.
Here’s the way I want to use the accordion:

  <accordion> <!-- this element is actually separate view in a parent state of the accordion-group's below.-->
    <accordion-group  ui-sref="site.home.newsID_1"> <!-- accordion-groups will be generated with ng-repeat.-->
      <accordion-heading>
        News 1
      </accordion-heading>
      <p>This is</p>
    </accordion-group>
    <accordion-group  ui-sref="site.home.newsID_2">
      <accordion-heading>
        News 2
      </accordion-heading>
      <p>Home News's</p>
    </accordion-group>
    <accordion-group ui-sref="site.home.news.newsID_3">
      <accordion-heading>
        News 3
      </accordion-heading>
      <p>Preview and navigation</p>
    </accordion-group>
  </accordion>

Below’s the modified template of the accordion:

<div ng-mouseenter="isOpen = !isOpen" ng-mouseleave="isOpen = !isOpen">
  <div class="accordion-group" ng-class="{transparentBackground: isClicked}">

      <div class="accordion-heading">
        <a id="link" ui-sref="site" class="accordion-toggle" ng-click="isClicked = !isClicked" accordion-transclude="heading">
          {{heading}}
        </a>
      </div>

    <div class="accordion-body" collapse="!isOpen && !isClicked">
      <div class="accordion-inner" ng-transclude></div>  </div>
  </div>
</div>

Basically the ‘site.home.newsID_X’ need to replace the ‘site’ value of ui-sref within the template.
My attempt was to set the value of ui-sref attribute via the ‘element’ parameter from the accordionGroup directive’s linking function as shown below:

link: function(scope, element, attrs, accordionCtrl) {
  element.find('#link').attr("ui-sref", attrs.uiSref)
  [...]
}

This does update the target ui-sref, but ui-router does not generate the corresponding href from the referenced state’s url, so after the DOM is rendered I am getting

 <a ui-sref="site.home.newsID_1" href="#/site" rel="nofollow noreferrer noopener"></a>

instead of the expected

 <a ui-sref="site.home.newsID_1" href="#/site/home/newsID_1" rel="nofollow noreferrer noopener"></a>

What am I missing?
I appreciate your time,
Jared

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

I’m not sure if it’s new or not, but there’s a way to pass parameters when using ui-sref.
In your case it would be something like this:

ui-sref="site.home.news({ newsID: news.id })"

(for a site.home.news state in you app, with a newsID parameter in its corresponding URL, and considering news.id points to the news ID in the current $scope)

See the documentation here.

Method 2

Ok, I’ve solved my problem. It appears that I was confusing states with urls.

A link with ui-sref will trigger state change to a given state, and will optionally change/generate the url, if one is defined in the state. Also states themselves do not have parameters, but urls do.

Here’s my understanding of a state:
A state in ui-router refers to a state of the website defined in a given html template. This template can have defined ui-views, i.e. place-holders (that can be named) that will be populated by other states. Any state can target one or more ui-views inside other states’ template with respective html templates – i.e. they can put the content of those templates into ui-views of other states’ templates. Every state can have an associated url, which links the url in the browser with the state. If the url in the browser matches the url associated with a given state, the state of the website will change, i.e. the new state will populate referenced ui-views in other state’s templates, with contents of templates bound to views in the currently active state.
Urls follow hierarchy of states, but are independent of them, so a state ‘site.home’ can have a url of ‘/home/content’, which will be appended to a url associated with its parent state (‘site’), unless explicitly told not to.
Therefore a state change/transition can be triggered either by the ui-sref or by changing the url via href link or manually in the browser by the user.
Another way to trigger state change internally (for egz. in a controller which can also be defined for every state) is to use the $state.go(…) method.
Understanding that, I simply changed the ui-sref references to href urls. While this is not a direct solution to my problem, and I still do not understand why ui-router isn’t generating corresponding hrefs, it does make things work as expected. I am still to explore the use of $state.go() to accomplish my goal.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply