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

29,780

Solution 1

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.

Solution 2

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.

Share:
29,780
Jared Tomaszewski
Author by

Jared Tomaszewski

Updated on May 08, 2020

Comments

  • Jared Tomaszewski
    Jared Tomaszewski almost 4 years

    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"></a>
    

    instead of the expected

     <a ui-sref="site.home.newsID_1" href="#/site/home/newsID_1"></a>
    

    What am I missing?
    I appreciate your time,
    Jared