动态设置ui-sref Angularjs的值

83

我已经搜索过类似的问题,但出现的结果似乎有些不同。 我正在尝试动态更改链接的ui-sref = ''(此链接指向向导表单的下一部分,下一部分取决于下拉列表中所做的选择)。 我只是尝试根据选择框中的某些选择设置ui-sref属性。 当进行选择时,通过绑定到作用域属性,我可以更改ui-sref。 然而,链接无法正常工作,这是否可能? 谢谢

  <a ui-sref="form.{{url}}" >Next Section</a>

然后在我的控制器中,我这样设置了URL参数

switch (option) {
  case 'A': {
    $scope.url = 'sectionA';
  } break;
  case 'B': {
    $scope.url = 'sectionB';
  } break;
}

或者,我使用指令根据从下拉框中选择的选项生成具有所需ui-sref属性的超链接来使其工作。

然而,这意味着每次从下拉框中选择不同的选项时都必须重新创建链接,这会导致不良的闪烁效果。我的问题是,是否可以像我上面尝试简单更改控制器中url值那样更改ui-sref的值,还是每次进行选择时都必须像下面所做的那样使用指令重新创建整个元素?(仅为完整性而显示此内容)

Select option directive(此指令生成链接指令)

define(['app/js/modules/app', 'app/js/directives/hyperLink'], function (app) {
app.directive('selectUsage', function ($compile) {

    function createLink(scope,element) {
        var newElm = angular.element('<hyper-link></hyper-link>');
        var el = $(element).find('.navLink');
        $(el).html(newElm);
        $compile(newElm)(scope);
    }

    return {

        restrict: 'E',
        templateUrl: '/Client/app/templates/directives/select.html'

        ,link: function (scope, element, attrs) {

            createLink(scope, element);

            element.on('change', function () {
                createLink(scope,element);
            })
        }
    }
})

超链接指令

define(['app/js/modules/app'], function (app) {
app.directive('hyperLink', function () {

    return {
        restrict: 'E',
        templateUrl: '/Client/app/templates/directives/hyperLink.html',
        link: function (scope, element, attrs) { }
    }

})

超链接模板

<div>
    <button ui-sref="form.{url}}">Next Section</button>
</div>

13个回答

72

看起来这个是可以做到的。

ui-router的一位作者在GitHub上的面包屑引导我尝试以下操作:

<a ng-href="{{getLinkUrl()}}">Dynamic Link</a>

然后,在您的控制器中:

$scope.getLinkUrl = function(){
  return $state.href('state-name', {someParam: $scope.someValue});
};

事实证明,这样做非常有效,可以更改作用域值等。你甚至可以使“state-name”字符串常量引用作用域值,这也会更新视图中的href :-)

1
最干净的解决方案 - 值得一提的是,“独立于路由库”。 - Radek Anuszewski
1
这会强制 getLinkUrl() 在每个循环周期中被处理,非常频繁。在 getLinkUrl() 中放置一个 console.log,然后移动鼠标观察日志的增长。并不是说这种方法不起作用,只是有点混乱。 - Suamere
2
这是一个在三年前使用Angular 1.4编写的解决方案。当时,这是实现所需功能的唯一可行选项,因为那个版本的Angular。仅仅批评和贬低一个答案,甚至不费心提供替代解决方案(如果有的话),对任何人都没有帮助。 - RavenHursT
1
它确实有帮助。它向未来的观众暗示这可能不是最佳解决方案,他们应该寻找其他方法。那个评论没有任何“无建设性”的地方。如果有什么不建设性的话,那就是你的回应,对一个合理的批评者进行攻击(并假设事实不在证据之中,比如负评与评论有关)。 - Cody Gray
1
@FabioPicheli的回答提供了一个更为更新的本地解决方案,请务必查看。 - phazei
显示剩余2条评论

61

这里有一个正在工作的plunker。最简单的方法似乎是使用以下组合:

它们可以一起使用,如下所示:

<a ng-href="{{$state.href(myStateName, myParams)}}">

因此,在 这个 plunker 的基础上,有以下状态:

$stateProvider
  .state('home', {
      url: "/home",
      ...
  })
  .state('parent', {
      url: "/parent?param",
      ...
  })
  .state('parent.child', { 
      url: "/child",
      ...

我们可以更改这些值来动态生成 href
<input ng-model="myStateName" />
<input ng-model="myParams.param" />

请在 此处输入操作 中检查。

原文:

有一个可行的示例 如何 来实现我们所需的功能。但不能使用动态 ui-sref

正如我们可以在这里检查到的那样:https://github.com/angular-ui/ui-router/issues/395

问:是否不支持动态 ui-sref 属性?
答:正确。

但是我们可以使用 ui-router 的其他功能:[$state.go("statename")][5]

因此,这可能是控制器的内容:

$scope.items = [
  {label : 'first', url: 'first'},
  {label : 'second', url: 'second'},
  {label : 'third', url: 'third'},
];
$scope.selected = $scope.items[0];
$scope.gotoSelected = function(){
  $state.go("form." + $scope.selected.url);
};

这里是HTML模板:

<div>
  choose the url:
  <select
    ng-model="selected"
    ng-options="item.label for item in items"
  ></select>

  <pre>{{selected | json}}</pre>
  <br />
  go to selected
  <button ng-click="gotoSelected()">here</button>

  <hr />
  <div ui-view=""></div>
</div>

工作中的 example

注意:有更为更新的$state.go定义链接,但是我认为废弃的链接更加清晰易懂。


1
在我看来,这并没有完全实现所需的行为。 ui-sref 实际上在 ui-sref 指令初始化时设置锚点标记的 href 属性。我通常对于动态控制的锚点标记做以下操作:<a ui-sref="{{scopedStateName}}( { 'some-state-param': '{{scopedParamValue}}' })">My Dynamic Link</a>,显然,这种方法唯一的问题是 ui-sref 不会监视作用域变量的变化,因此 href 在后续值更改时不会更改。据我所知,ui-sref 不支持这项功能。 - RavenHursT
经过更多的研究,我认为我已经找到了一种实现动态生成href属性引用状态参数的方法。请查看下面的答案。 - RavenHursT
你是如何在使用ng-href时避免硬页面刷新的?我目前遇到了问题,因为ng-href不使用ui-router的$state.go()方法。 - a_dreb

29

看一下这个问题#2944

ui-sref不会监视状态表达式,你可以使用ui-stateui-state-params传递变量。

  <a data-ui-state="selectedState.state" data-ui-state-params="{'myParam':aMyParam}">
       Link to page {{selectedState.name}} with myParam = {{aMyParam}}
  </a>

还提供了一个演示,速度很快。


1
太好了。它不需要额外的逻辑,并且还支持ui-sref-active。 - Julia

2

我成功地以这种方式实现了它(虽然我是使用controllerAs变体,而不是通过$scope)。

模板

<button ui-sref="main({ i18n: '{{ ctrlAs.locale }}' })">Home</button>

控制器

var vm = this;
vm.locale = 'en'; // or whatever dynamic value you prepare

还可以查看 ui-sref 的文档,其中可以传递参数:

https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref


不,button 的行为与 a 相同,指令实际上会在编译时在按钮上创建一个 href 属性,但从不更新它。而且,单击按钮将始终转到 href 值的状态,而不是更新后的 ui-sref - Jens

2

在尝试了各种解决方案后,我发现问题出在angular.ui.router代码中。

问题出在ui.router update方法被触发时会使用ref.state,这意味着无法更新元素点击时使用的href值。

以下是两种解决方案:

自定义指令

    module.directive('dynamicSref', function () {
    return {
        restrict: 'A',
        scope: {
            state: '@dynamicSref',
            params: '=?dynamicSrefParams'
        },
        link: function ($scope, $element) {
            var updateHref = function () {
                if ($scope.state) {
                    var href = $rootScope.$state.href($scope.state, $scope.params);
                    $element.attr('href', href);
                }
            };

            $scope.$watch('state', function (newValue, oldValue) {
                if (newValue !== oldValue) {
                    updateHref();
                }
            });

            $scope.$watch('params', function (newValue, oldValue) {
                if (newValue !== oldValue) {
                    updateHref();
                }
            });

            updateHref();
        }
    };
});

使用它的HTML非常简单:

<a  dynamic-sref="home.mystate"
    dynamic-sref-params="{ param1 : scopeParam }">
    Link
</a>

修复 ui.router 代码:

在 angular.router.js 中,您会找到指令 $StateRefDirective(对于版本0.3,位于第4238行)。

将指令代码更改为:

function $StateRefDirective($state, $timeout) {
    return {
        restrict: 'A',
        require: ['?^uiSrefActive', '?^uiSrefActiveEq'],
        link: function (scope, element, attrs, uiSrefActive) {
            var ref = parseStateRef(attrs.uiSref, $state.current.name);
            var def = { state: ref.state, href: null, params: null };
            var type = getTypeInfo(element);
            var active = uiSrefActive[1] || uiSrefActive[0];
            var unlinkInfoFn = null;
            var hookFn;

            def.options = extend(defaultOpts(element, $state), attrs.uiSrefOpts ? scope.$eval(attrs.uiSrefOpts) : {});

            var update = function (val) {
                if (val) def.params = angular.copy(val);
                def.href = $state.href(ref.state, def.params, def.options);

                if (unlinkInfoFn) unlinkInfoFn();
                if (active) unlinkInfoFn = active.$$addStateInfo(ref.state, def.params);
                if (def.href !== null) attrs.$set(type.attr, def.href);
            };

            if (ref.paramExpr) {
                scope.$watch(ref.paramExpr, function (val) { if (val !== def.params) update(val); }, true);
                def.params = angular.copy(scope.$eval(ref.paramExpr));
            }

            // START CUSTOM CODE : Ability to have a 2 way binding on ui-sref directive
            if (typeof attrs.uiSrefDynamic !== "undefined") {
                attrs.$observe('uiSref', function (val) {
                    update(val);

                    if (val) {
                        var state = val.split('(')[0];
                        def.state = state;

                        $(element).attr('href', $state.href(def.state, def.params, def.options));
                    }
                });
            }
            // END OF CUSTOM CODE

            update();

            if (!type.clickable) return;
            hookFn = clickHook(element, $state, $timeout, type, function () { return def; });
            element.bind("click", hookFn);
            scope.$on('$destroy', function () {
                element.unbind("click", hookFn);
            });
        }
    };
}

2
除非你创建自己的 angular-ui-router 分支,否则我建议不要这样做。你的同事可能会尝试更新它,然后 ,谁也不知道 bug 是从哪里来的。 - Rafael Herscovici

1
最佳方法是在按钮的ng-click指令中利用uiRouter的$state.go('stateName', {params})。如果没有选择选项,则禁用该按钮。
<select ng-model="selected" ng-options="option as option.text for option in options"></select>
<button ng-disabled="!selected" type="button" ng-click="ctrl.next()">Next</button>

控制器

function Controller($scope, $state){
    this.options = [{
        text: 'Option One',
        state: 'app.one',
        params: {
            param1: 'a',
            param2: 'b'
        }
    },{
        text: 'Option Two',
        state: 'app.two',
        params: {
            param1: 'c',
            param2: 'd'
        }
    },{
        text: 'Option Three',
        state: 'app.three',
        params: {
            param1: 'e',
            param2: 'f'
        }
    }];

    this.next = function(){
        if(scope.selected){
            $state.go($scope.selected.state, $scope.selected.params || {});
        }
    };
}

State

$stateProvider.state('wizard', {
    url: '/wizard/:param1/:param2', // or '/wizard?param1&param2'
    templateUrl: 'wizard.html',
    controller: 'Controller as ctrl'
});

1
这不适用于ui-sref-active或ui-sref-active-eq。 - KFE

1
来回答你的问题 :)
幸运的是,你不需要使用一个按钮来实现ng-click,或者在ng-href中使用一个函数来达到你所需求的。相反;
您可以在控制器中创建一个$scope变量,并将ui-sref字符串分配给它,并在视图中使用它,作为ui-sref属性。
就像这样:
// Controller.js

// if you have nasted states, change the index [0] as needed.
// I'm getting the first level state after the root by index [0].
// You can get the child by index [1], and grandchild by [2]
// (if the current state is a child or grandchild, of course).
var page = $state.current.name.split('.')[0];
$scope.goToAddState = page + ".add";


// View.html
<a ui-sref="{{goToAddState}}">Add Button</a>

这对我来说完美运作。

2
我尝试了你的方法,我可以看到 ui-sref 但是没有生成 href。有什么建议吗? - Arepalli Praveenkumar
2
ui-sref是一个指令,如果提供的状态具有URL(但在这种情况下显然不是),则在元素上设置href属性。 - askmike
我是否应该提到,为了使ui-sref生成href属性,您应该注册适当的状态?在我的示例中,我有一个由点分隔的状态层次结构。没有点是父级,有一个点是子级,有两个点是孙子级,以此类推...确保您正确注册状态,涉及到这种层次结构。 - ilter
3
第一次使用时,这样是有效的,但没有双向绑定 - 当作用域改变时,链接不会更新。 - Ben
2
我只能代表自己说,但在我的情况下,这是因为答案对问题无效。当下拉列表更改时,您将不再拥有有效的链接。 - Josh Gagnon
显示剩余3条评论

1
<a ng-click="{{getLinkUrl({someParam: someValue})}}">Dynamic Link</a>

$scope.getLinkUrl = function(value){
  $state.go('My.State',{someParam:value});

}

它返回一个对象。

0

这对我来说很有效

在控制器中

$scope.createState = 'stateName';

在视图中

ui-sref="{{ createState }}"

5
正如其他回答中@ben所指出的:这个方法第一次使用时有效,但是它没有双向绑定——当作用域发生变化时,链接不会更新。 - Jens

0
<ul class="dropdown-menu">
  <li ng-repeat="myPair in vm.Pairs track by $index">
     <a ui-sref="buy({myPairIndex:$index})"> 
          <span class="hidden-sm">{{myPair.pair}}</span>
     </a>
  </li>
</ul>

如果有人只想在Angularjs中动态设置ui-sref$stateParams。 注意:在检查元素中,它仍将显示为“buy({myPairIndex:$index})”,但$index将在该状态中获取。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接