当使用ui-router-extras粘性状态时,如何避免将$ state注入$ rootScope?

时间:2015-02-07 13:40:26

标签: angularjs angular-ui-router angular-ui-router-extras

对于粘性状态的ui-router-extras,

The example告诉我们,我们需要使用ng-show结合$ state来显示/隐藏自己的视图。因此,我们需要以某种方式使$ state可访问,在示例中通过将$ state全局注入$ rootScope来完成。

我不喜欢这个变量全局爬行我的范围并且从本地所有控制器中注入该变量的想法也不是最佳的。我怎样才能更优雅地解决这个问题?

2 个答案:

答案 0 :(得分:3)

这是自定义指令的完美应用程序。这是一个简单的指令,您可以将其添加到您的ui-view标记中:

 app.directive("showWhenStateActive", function($state) {
    return {
      restrict: 'A',
      link: function(scope, elem, attrs) {
        var stateChangedFn = function stateChanged() {
          var addOrRemoveFnName = $state.includes(attrs.showWhenStateActive) ? "removeClass" : "addClass";
          elem[addOrRemoveFnName]("ng-hide");
        };
        scope.$on("$stateChangeSuccess", stateChangedFn);
      }
    }
  });

要使用此功能,只需将其作为属性添加到标记中,然后提供要检查的状态名称。

例如,在ui-router-extras Sticky State example上,您将改变:

<div class="tabcontent well-lg" ui-view="peopletab" ng-show="$state.includes('top.people')" class="col-sm-6"></div>
<div class="tabcontent well-lg" ui-view="invtab"    ng-show="$state.includes('top.inv')"    class="col-sm-6"></div>
<div class="tabcontent well-lg" ui-view="custtab"   ng-show="$state.includes('top.cust')"   class="col-sm-6"></div>

到此:

<div class="tabcontent well-lg" ui-view="peopletab" show-when-state-active="top.people" class="col-sm-6"></div>
<div class="tabcontent well-lg" ui-view="invtab"    show-when-state-active="top.inv"    class="col-sm-6"></div>
<div class="tabcontent well-lg" ui-view="custtab"   show-when-state-active="top.cust"   class="col-sm-6"></div>

答案 1 :(得分:0)

我研究了source codeui-sref directive,以确定我是否可以构建类似的指令,但不是根据当前状态设置活动类,而是改变当前元素的可见性

不幸的是,ui-router似乎不打算以这种方式扩展。但是,我可以一起破解我自己的指令。请注意,parseStateRefstateContext是ui-router源代码中的复制和粘贴功能,其他代码无法访问这些功能。

源代码按照预期在我当前的项目中工作,但是我不知道在我的项目中我没有想到/需要哪些案例。

无论如何:用法是<... show-on-sref="targetState">。我成功地使用子相对链接(以点.someState开头的那些)来测试该指令。

var attributeName = 'showOnSref';

function parseStateRef(ref, current) {
    var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed;
    if (preparsed) ref = current + '(' + preparsed[1] + ')';
    parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/);
    if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'");
    return { state: parsed[1], paramExpr: parsed[3] || null };
}
function stateContext(el) {
    var stateData = el.parent().inheritedData('$uiView');

    if (stateData && stateData.state && stateData.state.name) {
        return stateData.state;
    }
}

angular
    .module('showOnSref', [])
    .directive(attributeName, ['$state', function($state) {
        return {
            restrict: 'A',
            link: function(scope, element, attrs) {
                var ref = parseStateRef(attrs[attributeName], $state.current.name),
                    linkedState = $state.get(ref.state, stateContext(element)),
                    params = angular.copy(scope.$eval(ref.paramExpr)),
                    inactiveClass = 'ng-hide',
                    bind = angular.bind,
                    show = bind(element, element.removeClass, inactiveClass),
                    hide = bind(element, element.addClass, inactiveClass),
                    update = function() {
                        $state.includes(linkedState.name, params) ? show() : hide();
                    };
                    scope.$on('$stateChangeSuccess', update);
            }
        };
    }]);