Как удалить ранее предоставленный необязательный параметр при изменении состояния с помощью ui-router

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

Есть ли способ убедиться, что необязательный параметр удаляется из-за изменений состояния?

Это пример того, как я хочу изменить состояние (тест a и тест b), но оказывается, что я должен использовать версию test d из-за сохранения необязательного параметра, если он был использован ранее,

<a ui-sref="test({req: 'a'})">test a</a><br/>
<a ui-sref="test({req: 'b'})">test b</a><br/>
<a ui-sref="test({req: 'c', opt: 'here'})">test c and opt</a><br/>
<a ui-sref="test({req: 'd', opt: undefined})">test d and explicity without opt</a>

Это похоже на то, как настроено мое состояние:

        $stateProvider.state('test', {
            url: '/{req}?opt',
            params: {
                opt: {value: null, squash: true}
            },
            template: '<h1>req = {{req}}</h1>' +
                    '<h1>opt = {{opt}}</h1>',
            controller: function($scope, $stateParams) {
                $scope.req = $stateParams.req; 
                $scope.opt = $stateParams.opt;
            }
        })

Вот jsfiddle. Нажмите на первые две ссылки, и он работает так, как ожидалось, но как только вы нажмете на 3-ей ссылке, а затем щелкните по одной из первых двух ссылок, вы увидите, что дополнительный параметр сохраняется, хотя он опущен в первые две ссылки.

Я бы предпочел, чтобы не было явно reset необязательный параметр и действительно ли он работал, если он является необязательным.

Любые идеи? Так ли оно работает? Если да, есть ли способ заставить его работать так, как я хочу? Или я обнаружил ошибку?

Обновление

Похоже, что сохранение необязательного параметра "как было разработано" на основе одного из приведенных ниже ответов. Тем не менее, я по-прежнему смотрю на эффективное обходное решение, если это возможно. Я перехожу в состояние из множества мест в моем приложении, и 99% из них не указывают необязательный параметр. Я бы предпочел не изменять все эти переходы и не знать о необязательном параметре, а вместо этого указывать только необязательный параметр в 1% времени, в котором я нуждаюсь.

Я попытался создать два состояния "test" и дочерний "test.opt", а затем перейти к "тестированию" в обычном режиме (например, "test a" и "test b" ), и только переход к "test.opt", когда я указываю необязательный параметр. Тем не менее, у меня есть решение, которое вызывает вызов для отдыха, и ему нужно знать, установлен ли параметр opt, поэтому он не работает, поскольку решение не может получить доступ к "opt" из дочернего элемента.

Обновление # 2

Я также попытался создать дубликат состояния "test" с именем "testopt", и в этом случае единственное отличие - параметр "opt". Однако очевидно, что ui-router не может различать два URL-адреса, которые отличаются только параметром запроса, и поэтому он все же пытается перейти на "тест", даже если opt param является частью URL-адреса.

Ответ 1

Просто добавьте опцию ui-sref-opts inherit = false к вашим ссылкам:

<a ui-sref="test({req: 'a'})" ui-sref-opts="{inherit: false}">test a</a><br/>
<a ui-sref="test({req: 'b'})" ui-sref-opts="{inherit: false}">test b</a><br/>
<a ui-sref="test({req: 'c', opt: 'here'})" ui-sref-opts="{inherit: false}">test c and opt</a><br/>
<a ui-sref="test({req: 'd', opt: undefined})" ui-sref-opts="{inherit: false}">test d and explicity without opt</a>

Тема, которая документирует этот запрос и реализацию этой функции: https://github.com/angular-ui/ui-router/issues/376

---- EDIT ----

Так как вышеупомянутое решение не кажется идеальным, поскольку оно также требует обновления (и поддержания) каждого из якорей si-sref для установки желаемого поведения, другим решением может быть переопределение метода состояния go(...) для установки inherit опция false по умолчанию. Хотя я не уверен, что это рекомендуемый шаблон, чтобы сделать это, измените свой .config на следующее:

.config(['$stateProvider', '$provide', function ($stateProvider, $provide) {
    $stateProvider.state('test', {
        url: '/{req}?opt',
        params: {
            opt: {value: null, squash: true}
        },
        template: '<h1>req = {{req}}</h1>' +
            '<h1>opt = {{opt}}</h1>',
        controller: function($scope, $stateParams) {
            $scope.req = $stateParams.req; 
            $scope.opt = $stateParams.opt;
        }
    });

    $provide.decorator('$state', function ($delegate) {
        var state = $delegate;

        state.baseGo = state.go;

        var go = function (to, params, options) {
            options = options || {};

            if (angular.isUndefined(options.inherit)) {
                options.inherit = false;
            }

            this.baseGo(to, params, options);
        };

        state.go = go;
        return $delegate;
    });
}])

Ответ 2

У меня была та же проблема, из-за наследования по умолчанию параметров... Чтобы завершить предыдущий ответ, синтаксис для вызова JS:

$state.go('new state', {pararemeters... } , {inherit:false});