Stellen Sie den Wert von ui-sref Angularjs dynamisch ein


78

Ich habe nach einer ähnlichen Frage gesucht, aber die, die auftauchten, scheinen etwas anders zu sein. Ich versuche, das ui-sref = '' eines Links dynamisch zu ändern (dieser Link verweist auf den nächsten Abschnitt eines Assistentenformulars und der nächste Abschnitt hängt von der Auswahl in der Dropdown-Liste ab). Ich versuche einfach, das Attribut ui-sref abhängig von einer Auswahl in einem Auswahlfeld festzulegen. Ich kann das ui-sref ändern, indem ich es an ein Bereichsattribut binde, das festgelegt wird, wenn eine Auswahl getroffen wird. Der Link funktioniert jedoch nicht. Ist dies überhaupt möglich? Vielen Dank

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

und dann setze ich in meinem Controller den URL-Parameter auf diese Weise

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

Alternativ habe ich Anweisungen verwendet, um es zum Laufen zu bringen, indem ich den Hyperlink mit dem gewünschten ui-sref-Attribut gemäß der im Auswahlfeld ausgewählten Option (Dropdown) generiert habe.

Dies bedeutet jedoch, dass ich den Link jedes Mal neu erstellen muss, wenn eine andere Option aus dem Auswahlfeld ausgewählt wird, die einen unerwünschten Flackereffekt verursacht. Meine Frage ist, ob es möglich ist, den Wert der UI-Sref wie oben beschrieben zu ändern, indem der Wert der URL in meinem Controller vereinfacht wird, oder ob ich das gesamte Element bei jeder Auswahl mithilfe einer Direktive neu erstellen muss wird gemacht wie ich unten gemacht habe? (Nur der Vollständigkeit halber)

Optionsanweisung auswählen (diese Anweisung generiert die Linkanweisung)

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

Hyperlink-Direktive

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

})

Hyperlink-Vorlage

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

Antworten:


67

Sieht so aus, als wäre das doch möglich.

Ein Breadcrumb auf GitHub von einem der UI-Router-Autoren veranlasste mich, Folgendes zu versuchen:

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

Dann in Ihrem Controller:

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

Es stellt sich heraus, dass dies wie ein Zauber funktioniert, bei dem sich die Werte des Bereichs und alles ändern. Sie können sogar die Zeichenfolgenkonstantenreferenz 'state-name' zu einem Gültigkeitsbereich machen, wodurch auch die href in der Ansicht aktualisiert wird :-)


1
Sauberste Lösung - und was erwähnenswert ist: "Router-Bibliothek unabhängig".
Radek Anuszewski

1
Dies zwingt getLinkUrl () dazu, in jedem Digest-Zyklus verarbeitet zu werden, was SEHR häufig vorkommt. Stecke ein console.log in getLinkUrl () und bewege einfach deine Maus über die Seite und beobachte, wie dein Log explodiert. Nicht zu sagen, dass diese Methode nicht funktioniert, sie ist nur chaotisch.
Suamere

2
Dies war eine Lösung, die vor über 3 Jahren in Angular 1.4 geschrieben wurde. Es war damals die einzig praktikable Option, mit dieser Version von Angular die gewünschte Funktionalität zu erreichen. Nur eine Antwort zu kritisieren und abzustimmen, ohne sich die Mühe zu machen, eine alternative Lösung zu geben (falls es eine gibt), hilft niemandem.
RavenHursT

1
Es hilft absolut . Dies legt zukünftigen Zuschauern nahe, dass dies möglicherweise nicht die beste Lösung ist und sie sich anderswo umsehen sollten. An diesem Kommentar war nichts "Unkonstruktives". Wenn etwas nicht konstruktiv war, war es Ihre Antwort, die einen Benutzer wegen einer gültigen Kritik anpeitschte (und Tatsachen voraussetzte, die nicht belegt waren, wie die Ablehnung, die mit dem Kommentar verbunden war).
Cody Gray

1
Die Antwort von @ FabioPicheli bietet eine aktuellere native Lösung. Schauen Sie sich diese an.
Phazei

61

Es gibt einen funktionierenden Plunker . Der einfachste Weg scheint darin zu bestehen, eine Kombination aus:

  • $state.href() (doc hier ) und
  • ng-href (doc hier )

Diese zusammen könnten verwendet werden als:

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

Also (nach diesem Plunker ) mit solchen Zuständen:

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

Wir können diese Werte ändern, um die href dynamisch zu generieren

<input ng-model="myStateName" />
<input ng-model="myParams.param" />

Überprüfen Sie es hier in Aktion

ORIGINAL:

Es gibt ein funktionierendes Beispiel, wie wir das erreichen können, was wir brauchen. Aber nicht mit Dynamik ui-sref.

Wie wir hier überprüfen können: https://github.com/angular-ui/ui-router/issues/395

F: Werden dynamische UI-Sref-Attribute nicht unterstützt?
A: Richtig.

Wir können jedoch verschiedene Funktionen verwenden ui-router:[$state.go("statename")][5]

Das könnte also das Controller-Zeug sein:

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

Und hier ist die HTML-Vorlage:

<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>

Das Arbeitsbeispiel

HINWEIS: Es gibt einen aktuelleren Link zur Definition von $ state.go , aber der veraltete ist mir etwas klarer


1
IMHO erreicht dies nicht vollständig das gewünschte Verhalten. ui-sref setzt das href-Attribut des Ankertags bei der Initialisierung der ui-sref-Direktive. Was ich normalerweise für dynamisch gesteuerte <a ui-sref="{{scopedStateName}}( { 'some-state-param': '{{scopedParamValue}}' })">My Dynamic Link</a> Ankertags mache, ist ungefähr das Folgende: Das einzige Problem bei diesem Ansatz ist natürlich, dass ui-sref nicht auf Änderungen in den Gültigkeitsbereichsvariablen achtet, sodass sich die href bei nachfolgenden Wertänderungen nicht ändert . AFAIK, ui-sref unterstützt dies nicht.
RavenHursT

Nach ein wenig mehr Recherche habe ich einen Weg gefunden, dynamisch generierte href-Attribute zu erstellen, die auf Zustände mit Zustandsparametern verweisen. Bitte sehen Sie meine Antwort unten.
RavenHursT

Wie vermeiden Sie eine harte Seitenaktualisierung bei Verwendung von ng-href? Ich habe derzeit Probleme mit dieser Lösung, da ng-href keine UI-Router- $state.go()Methode verwendet.
Andre

27

Schauen Sie sich diese Ausgabe Nr. 2944 an .

Der ui-srefStatusausdruck wird nicht überwacht. Sie können die Variable verwenden ui-stateund ui-state-paramsübergeben.

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

Auch eine schnelle Demo im Ticket.


1
Toll. Es erfordert keine zusätzliche Logik und unterstützt auch ui-sref-active
Julia

2

Ich habe es auf diese Weise implementiert (ich verwende jedoch die controllerAs-Variante - nicht über $ scope).

Vorlage

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

Regler

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

ui-srefLesen Sie auch die Dokumentation, an die Sie Parameter übergeben können:

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


Nein, buttonverhält sich genauso wie adie Direktive, die hrefbeim Kompilieren tatsächlich ein Attribut auf der Schaltfläche erstellt, dieses jedoch nie aktualisiert. Und ein Klick auf die Schaltfläche wird immer zum Status des hrefWertes der aber nicht der aktualisiertenui-sref
Jens

2

Nachdem ich verschiedene Lösungen ausprobiert hatte, fand ich das Problem im angular.ui.routerCode.

Das Problem ergibt sich aus der Tatsache, dass die ui.router- updateMethode mit ausgelöst wird, ref.statewas bedeutet, dass es nicht möglich ist, den Wert des hrefverwendeten zu aktualisieren , wenn auf das Element geklickt wird.

Hier sind 2 Lösungen, um das Problem zu lösen:

Benutzerdefinierte Richtlinie

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

Der HTML-Code ist recht einfach:

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

Fix ui.router Code:

In angular.router.js finden Sie die Direktive $StateRefDirective(Zeile 4238 für Version 0.3).

Ändern Sie den Direktivencode in:

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
Wenn Sie nicht Ihre eigene Gabel erstellen, angular-ui-routerwürde ich dagegen vorschlagen. Ihr Kollege könnte versuchen, es zu aktualisieren und zu boomen , niemand weiß, woher der Fehler kam.
Rafael Herscovici

1

Kam, um das für immer zu beantworten :)

Glücklicherweise müssen Sie keine Schaltfläche für ng-click verwenden oder eine Funktion in ng-href verwenden , um das zu erreichen, was Sie suchen. Stattdessen;

Sie können eine $scopeVariable in Ihrem Controller erstellen , die ui-srefZeichenfolge darin zuweisen und in Ihrer Ansicht als ui-srefAttribut verwenden.

So was:

// 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>

Das funktioniert perfekt für mich.


1
Ich habe Ihren Ansatz versucht, ich kann sehen, ui-srefaber hrefnicht generiert.
Alle

Ich habe "href" nirgendwo in meiner Antwort erwähnt. Wie ist das relevant?
ilter

1
ui-sref ist eine Direktive, die ein href-Attribut für ein Element festlegt, wenn der angegebene Status eine URL hat (in diesem Fall jedoch anscheinend nicht).
Askmike

2
@ilter Dies funktioniert beim ersten Mal, aber es gibt keine bidirektionale Bindung - der Link wird nicht aktualisiert, wenn sich der Bereich ändert.
Ben

1
Ich kann nur für mich selbst sprechen, aber in meinem Fall liegt es daran, dass die Antwort für die Frage nicht funktioniert. Wenn sich die Dropdown-Liste ändert, haben Sie keinen gültigen Link mehr.
Josh Gagnon

1

Der beste Ansatz besteht darin, uiRouter's $state.go('stateName', {params})die ng-clickDirektive von button zu verwenden . Deaktivieren Sie die Schaltfläche, wenn keine Option ausgewählt ist.

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>

Regler

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

Zustand

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

1
Dies funktioniert nicht mit ui-sref-active oder ui-sref-active-eq
KFE

0

Das funktioniert nur für mich

in der Steuerung

$scope.createState = 'stateName';

im Hinblick auf

ui-sref="{{ createState }}"

4
Wie von @ben in den anderen Antworten angemerkt: Dies funktioniert beim ersten Mal, aber es gibt keine bidirektionale Bindung - der Link wird nicht aktualisiert, wenn sich der Umfang ändert
Jens

0

Für die Verwaltung mehrerer dynamischer Parameter mit ui-sref hier meine Lösung:

Html: ('MyPage.html')

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

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

Genießen !


Es gibt mir einen Fehler, der besagt, dass ich vom aktuellen Status nicht zu myState navigieren kann
Mani

@Mani Benutzt du einen UI -Router ? Ist es möglich, Ihren Code zu sehen?
Emidomenge

Ja, ich benutze UI-Router. <ion-item class = "Akkordeon-Item" ng-repeat = "Item in group.items" ng-show = "isGroupShown (group)" ui-sref = "{{item.state}}" ui-sref-active = "iactive"> {{item.title}} </ ion-item>
Mani

versuchen ui-sref="item.state"
Emidomenge

Es funktioniert nur mit Blütenklammern. Es tut mir Leid. Es gab einen anderen Ort, an dem ich einen Fehler gemacht habe. Es tut uns leid.
Mani

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>

Wenn jemand nur die $ stateParams von ui-sref in Angularjs dynamisch setzen möchte. Hinweis: Im Inspect-Element wird es weiterhin als "buy ({myPairIndex: $ index})" angezeigt, aber in diesem Status wird $ index abgerufen.


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

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

}

Es gibt ein Objekt zurück


-1

Oder einfach so:

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

3
Wie von @ben in den anderen Antworten angemerkt: Dies funktioniert beim ersten Mal, aber es gibt keine bidirektionale Bindung - der Link wird nicht aktualisiert, wenn sich der Bereich ändert
Jens

Ich versuche diese Methode, konnte aber keinen Vorschlag machen oder
Aswin
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.