Динамічно встановлюйте значення ui-sref Angularjs


79

Я шукав подібне запитання, але ті, що виникали, здаються дещо іншими. Я намагаюся динамічно змінити 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 відповідно до опції, вибраної у полі вибору (спадне меню).

Однак це означає, що мені доводиться відтворювати посилання щоразу, коли з поля вибору вибирається інший варіант, що спричиняє небажаний ефект мерехтіння. Моє запитання полягає в наступному: чи можна змінити значення ui-sref, як я спробував зробити вище, спростивши зміну значення url у своєму контролері, або мені доводиться відтворювати весь елемент за допомогою директиви кожного разу, коли виділення зроблено так, як це зроблено нижче? (просто показуючи це для повноти)

Виберіть параметр директиви (ця директива генерує директиву посилання)

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>

Відповіді:


68

Здається, це все-таки можливо зробити.

Схема на GitHub одного з авторів користувальницького інтерфейсу змусила мене спробувати наступне:

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

Потім у вашому контролері:

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

Виявляється, це працює як шарм зі зміною значень масштабу та все. Ви навіть можете зробити посилання на константу 'state-name' рядковим значенням, яке також оновить href у поданні :-)


1
Найчистіше рішення - і те, що варто згадати, "незалежний від маршрутизатора-бібліотеки".
Радек Анушевський,

1
Це змушує getLinkUrl () оброблятися в кожному циклі дайджесту, що ДУЖЕ часто. Вставте console.log в getLinkUrl () і просто проведіть мишею по сторінці і спостерігайте, як ваш журнал підривається. Не кажучи, що цей метод не працює, він просто брудний.
Суамер

2
Це рішення було написано в Angular 1.4 понад 3 роки тому. Тоді це був єдиний життєздатний варіант досягнення бажаної функціональності за допомогою цієї версії Angular. Просто критикувати і не голосувати за відповідь, навіть не намагаючись дати альтернативне рішення (якщо воно є), нікому не допомагає.
RavenHursT

1
Це абсолютно робить допомогу. Це передбачає майбутнім глядачам, що це може бути не найкращим рішенням, і вони повинні шукати деінде. У цьому коментарі не було нічого "неконструктивного". Якщо що-небудь було неконструктивним, це була ваша відповідь, кидаючись на користувача за вагому критику (і припускаючи факти, які не є доказовими, як-от голос проти був підключений до коментаря).
Коді Грей

1
Відповідь @ FabioPicheli надає більш оновлене власне рішення, обов’язково перевірте його.
phazei

61

Є робочий плункер . Здається, найпростішим способом є використання комбінації:

  • $state.href() (документ тут ) та
  • ng-href (документація тут )

Вони разом можуть бути використані як:

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

Отже, (після цього плункера ) маємо такі стани:

$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

З: [A] чи не підтримуються динамічні атрибути 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>

Робочий приклад

ПРИМІТКА: є більш сучасне посилання на визначення $ state.go , але застаріле для мене трохи зрозуміліше


1
ІМХО, це не повністю забезпечує бажану поведінку. ui-sref фактично встановлює атрибут href тегу прив'язки при ініціалізації директиви ui-sref. Що я зазвичай роблю для динамічно керованих прив'язних тегів, це приблизно наступне: <a ui-sref="{{scopedStateName}}( { 'some-state-param': '{{scopedParamValue}}' })">My Dynamic Link</a> Єдина проблема цього підходу, очевидно, полягає в тому, що ui-sref не стежить за змінами в обсязі змінних, тому href не змінюється при наступних змінах значень . AFAIK, ui-sref цього не підтримує.
RavenHursT

Після трохи більше досліджень, я думаю, я знайшов спосіб виконати динамічно генеровані атрибути href, що посилаються на стани з параметрами стану. Будь ласка, дивіться мою відповідь нижче.
RavenHursT

Як ви уникаєте жорсткого оновлення сторінки під час використання ng-href? Зараз у мене проблеми з цим рішенням, оскільки ng-href не використовує $state.go()метод ui-routers .
Андре

27

Погляньте на це випуск № 2944 .

Якщо ui-srefне виглядає вираз стану, ви можете використовувати ui-stateта ui-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
Джулія

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
Йенс

2

Спробувавши різні рішення, я знайшов проблему в angular.ui.routerкоді.

Проблема випливає з того, що updateметод ui.router запускається, ref.stateщо означає, що неможливо оновити значення hrefвикористовуваного при натисканні елемента.

Ось 2 рішення для вирішення проблеми:

Спеціальна директива

    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 (рядок 4238 для версії 0.3).

Змініть код директиви на:

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я б запропонував проти. Ваш колега-співробітник може спробувати оновити його і процвітати , ніхто не знає, звідки виникла помилка.
Рафаель Герсковічі

1

Прийшов відповісти, що назавжди :)

На щастя, вам не потрібно використовувати кнопку для натискання нг або використовувати функцію всередині ng-href, щоб досягти того, що ви шукаєте. Натомість;

Ви можете створити $scopevar у своєму контролері та призначити в ньому 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>

Це ідеально для мене працює.


1
Я спробував ваш підхід, я бачу, ui-srefале hrefне згенерований. Будь-які пропозиції
Арепаллі Правенкумар

Я ніде не згадував "href" у своїй відповіді. Як це актуально?
ilter

1
ui-sref - це директива, яка встановлює атрибут href для елемента, якщо наданий стан має URL-адресу (але в цьому випадку, мабуть, ні).
askmike

2
@ilter це працює вперше, але немає жодних двосторонніх прив'язок - посилання не оновлюється при зміні області дії.
Бен

1
Я можу говорити лише за себе, але в моєму випадку це тому, що відповідь не працює на питання. Коли спадне меню зміниться, у вас більше не буде дійсного посилання.
Джош Ганьон

1

Найкращий підхід - використовувати директиву uiRouter's $state.go('stateName', {params})on button ng-click. І вимкніть кнопку, якщо не вибрано жодної опції.

HTML

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

Держава

$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
<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 }}"

4
як зазначає @ben в інших відповідях: це працює вперше, але немає жодних двосторонніх прив’язок - посилання не оновлюється при зміні обсягу
Єнс

0

Для управління кількома динамічними параметрами за допомогою ui-sref, ось моє рішення:

Html: ('MyPage.html')

<button type="button" ui-sref="myState(configParams())">

Контролер: ('MyCtrl')

.controller('MyCtrl', function ($scope) {
  $scope.params = {};
  $scope.configParams = function() {
    $scope.params.param1 = 'something';
    $scope.params.param2 = 'oh again?';
    $scope.params.param3 = 'yes more and more!';
    //etc ...

    return $scope.params;
  };
}

stateProvider: ('myState')

 $stateProvider
          .state('myState', {
            url: '/name/subname?param1&param2&param3',
            templateUrl: 'MyPage.html',
            controller: 'MyCtrl'
          });

Насолоджуйтесь!


Це видає мені помилку, в якій зазначається, що я не можу перейти до myState із поточного стану
Мані

@Mani Чи використовуєш користувальницький інтерфейс ? Чи можна побачити ваш код?
Emidomenge

Так, я використовую користувальницький інтерфейс. <ion-item class = "accordion-item" ng-repeat = "item in group.items" ng-show = "isGroupShown (group)" ui-sref = "{{item.state}}" ui-sref-active = "iactive"> {{item.title}} </ion-item>
Мані

спробуй ui-sref="item.state"
Emidomenge

його робота лише з квітковими брекетами. Вибачте. Було ще десь я помилився. Вибачте.
Мані

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>

Якщо хто - то хоче тільки динамічно встановити $ stateParams з UI-sref в Angularjs. Примітка: В елементі inspect він все одно відображатиметься як "buy ({myPairIndex: $ index})", але $ index буде завантажено в такому стані.


-1

Або просто щось на зразок цього:

<a ui-sref="{{ condition ? 'stateA' : 'stateB'}}">
  Link
</a>

3
як зазначає @ben в інших відповідях: це працює вперше, але не існує жодного двостороннього прив’язки - посилання не оновлюється, коли змінюється область дії
Йенс

Я пробую цей метод, але не міг змусити його викликати будь-яку пропозицію або
Асвін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.