如何实现“ui-sref”有条件执行?

时间:2014-09-01 06:36:26

标签: javascript angularjs angular-ui-router

我想在浏览器遵循ui-router动态创建的链接之前验证某些条件。

我正在调查$rootscope.$on('$stateChangeStart', ..),但我无法访问controller.$scope。我还需要在应用程序的几个地方使用它,并且会很麻烦。

请注意,ui-srefui-sref-active(一起工作)相关联,因此我无法删除ui-sref,也就是说,使用$state.$go('some-state')在使用ng-click调用的函数中。

条件应该在$scope functionon-click event内进行评估(转换前可以取消它)

我需要这样的东西:

<li ui-sref-active="active">
      <a ui-sref="somestate" ui-sref-if="model.validate()">Go Somestate</a>
</li>

我试过了:

<li ui-sref-active="active">
      <a ui-sref="somestate" ng-click="$event.preventDefault()">Go Somestate</a>
</li>

<li ui-sref-active="active">
      <a ui-sref="somestate" ng-click="$event.stopImmediatePropagation()">Go Somestate</a>
</li>

<li ui-sref-active="active">
    <a ui-sref="somestate">
       <span ng-click="$event.stopPropagation();">Go Somestate</span>
    </a>
</li>

即使

<li ui-sref-active="active">
      <a ui-sref="somestate" onclick="return false;">Go Somestate</a>
</li>

但是不起作用。

SANDBOX

9 个答案:

答案 0 :(得分:67)

answer启发我创建一个指令,允许我中断最终改变状态的事件链。为方便起见,其他用途也会阻止在同一元素上执行ng-click。

<强>的javascript

module.directive('eatClickIf', ['$parse', '$rootScope',
  function($parse, $rootScope) {
    return {
      // this ensure eatClickIf be compiled before ngClick
      priority: 100,
      restrict: 'A',
      compile: function($element, attr) {
        var fn = $parse(attr.eatClickIf);
        return {
          pre: function link(scope, element) {
            var eventName = 'click';
            element.on(eventName, function(event) {
              var callback = function() {
                if (fn(scope, {$event: event})) {
                  // prevents ng-click to be executed
                  event.stopImmediatePropagation();
                  // prevents href 
                  event.preventDefault();
                  return false;
                }
              };
              if ($rootScope.$$phase) {
                scope.$evalAsync(callback);
              } else {
                scope.$apply(callback);
              }
            });
          },
          post: function() {}
        }
      }
    }
  }
]);

<强> HTML

<li ui-sref-active="active">
      <a ui-sref="somestate" eat-click-if="!model.isValid()">Go Somestate</a>
</li>

PLUNKER

答案 1 :(得分:27)

您可以使用将返回的范围函数:

  • 无州
  • 现有状态

    像这样:

HTML:

<li ui-sref-active="active">
      <a ui-sref="{{checkCondition()}}">Go Somestate</a>
</li>

JS范围:

$scope.checkCondition = function() {
    return model.validate()
        ? 'someState'
        : '-' // hack: must return a non-empty string to prevent JS console error
}
仅当函数返回现有状态字符串时,才会创建

href属性。

或者,你可以做一个(丑陋的):

<li ui-sref-active="active">
      <a ui-sref="somestate" ng-if="model.validate()">Go Somestate</a>
      <span ng-if="!model.validate()">Go Somestate</span>
</li>

希望这有帮助

答案 2 :(得分:9)

有条件地实现路由而不修改指令,范围等的最简单的解决方法是我在这里找到的解决方法 - https://github.com/angular-ui/ui-router/issues/1489

<强> <a ui-sref="{{condition ? '.childState' : '.'}}"> Conditional Link </a>

答案 3 :(得分:7)

您可以随时加倍元素并有条件地显示/隐藏

    <li ui-sref-active="active">
          <a ng-show="condition1" style="color: grey">Start</a>
          <a ng-hide="condition1" ui-sref="start">Start</a>
    </li>

http://plnkr.co/edit/ts4yGW?p=preview

答案 4 :(得分:3)

无需复杂的指令或黑客攻击。以下工作正常,并允许单击非sref项目进行特定处理:

<a 
  ng-repeat="item in items" ui-sref="{{item.sref || '-'}}" 
  ng-click="$ctrl.click(item, $event)"
>...</a>

在控制器中,一个简单的点击处理程序,用于没有item.sref的项目:

this.click = function(item, event) {
  if (!item.sref) {
    event.preventDefault();
    //do something else
  }
};

答案 5 :(得分:2)

根据How to dynamically set the value of ui-sref的答案,您可以在范围内创建一个用于构建网址的功能:

$scope.buildUrl = function() {
  return $state.href('somestate', {someParam: 'someValue});
};

然后有条件地将其附加到ng-href

的链接
<a ng-href="{{ someCondition ? buildUrl() : undefined }}">Link</a>

正如您在下面的演示中所看到的,如果值为负数,则ng-href不会添加href属性。

&#13;
&#13;
angular.module('app', [])
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <a ng-href="{{ condition ? 'http://thecatapi.com/api/images/get?format=src&type=gif' : undefined}}">This is the link</a>
  <br>
  <label for="checkbox">
    <input type="checkbox" id="checkbox" ng-model="condition">
    Link active?
  </label>
</div>
&#13;
&#13;
&#13;

答案 6 :(得分:1)

我知道这是一个老问题,但为了将来的参考,我想提供一个替代解决方案,因为到目前为止我没有在任何答案中看到它。

<强>所需

<li ui-sref-active="active">
    <a ui-sref="somestate" ui-sref-if="model.validate()">Go Somestate</a>
</li>

潜在解决方案(模板):

<li ng-class="{ active: state.current.name === 'somestate' }">
    <a ng-click="navigateToState()">Go Somestate</a>
</li>

在控制器中:

$scope.state = $state;
$scope.navigateToState = navigateToState;

function navigateToState() {
  if ($scope.model.valid) {
    $state.go('somestate');
  }
}

答案 7 :(得分:0)

仍然需要ng-click处理ui-sref组件或其父级的人员的可能解决方案。

我的解决方案是使用href代替ui-sref并稍微修改Emanuel's指令,以便能够分别停止hrefng-click个调用。

Planker

虽然它有一些限制:

  • 不适用于ui-sref
  • 由于先前的限制,您应该为每个州设置不同的网址
  • ui-sref-active无法正常使用

答案 8 :(得分:0)

对于二进制情况(链接被启用或禁用),它“现在”(自 2018 年起)的工作方式如下(防止点击并将其设置为禁用):

<a ui-sref="go" ng-disabled="true">nogo</a>

以及其他标签:

<span ui-sref="go" ng-disabled="true">nogo</span>