Подтвердить что ты не робот

Как добиться того, чтобы "ui-sref" был условно выполнен?

Я хочу проверить некоторые условия перед тем, как браузер будет следовать за динамикой, созданной ui-router.

Я смотрел $rootscope.$on('$stateChangeStart', ..), но у меня нет доступа к controller.$scope. Я также должен использовать это в нескольких местах в приложении и будет громоздким.

Имейте в виду, что ui-sref связан с ui-sref-active (работать вместе), поэтому я не могу удалить ui-sref и, скажем, использовать $state.$go('some-state') внутри функции с ng-click.

Условие должно быть оценено внутри a $scope function и на on-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

4b9b3361

Ответ 1

Этот ответ вдохновил меня на создание директивы, которая позволяет мне прервать цепочку событий, которые в конечном итоге меняют состояние. Для удобства и других целей также предотвращает выполнение 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

Ответ 2

Вы можете использовать функцию области видимости, которая либо вернется:

  • нет состояния
  • существующее состояние

    так:

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>

Надеюсь, что это поможет

Ответ 3

Вы всегда можете удвоить элемент и показать/скрыть условно

    <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

Простейшим обходным путем для условного достижения маршрутизации без использования директив, области и т.д. было обходное решение, которое я нашел здесь - https://github.com/angular-ui/ui-router/issues/1489

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

Ответ 5

На основе ответов на Как динамически установить значение ui-sref вы можете создать функцию в своей области для создания URL-адреса:

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

И затем условно добавьте его к ссылке с ng-href

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

Как вы можете видеть в демонстрационной версии ниже, ng-href не добавляет атрибут href, если значение отрицательное.

angular.module('app', [])
<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>

Ответ 6

Нет необходимости в сложных директивах или хаках. Следующее работает отлично и позволяет осуществлять определенную обработку при нажатии элементов не 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
  }
};

Ответ 7

Я знаю, что это старый вопрос, но для будущей ссылки я хотел предложить альтернативное решение, так как я не видел его ни в одном из ответов.

Желаемая:

<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');
  }
}

Ответ 8

Возможное решение для тех, кому еще нужно ng-click работать с компонентом ui-sref или его родителями.

Мое решение состоит в том, чтобы использовать href вместо ui-sref и немного изменить директиву Emanuel, чтобы иметь возможность останавливать вызовы href и ng-click в отдельности.

Planker.

Хотя у него есть несколько ограничений:

  • не будет работать с ui-sref
  • у вас должны быть разные URL-адреса для каждого состояния из-за предыдущего ограничения
  • ui-sref-active не будет работать.