Reputation: 843
I have searched for a similar question but the ones that came up seem slightly different. I am trying to change the ui-sref='' of a link dynamically (this link points to the next section of a wizard form and the next section depends on the selection made on the dropdown list). I am simply trying to set the ui-sref attribute depending on some selection in a select box. I am able to change the ui-sref by binding to a scope attribute which is set when a selection is made. however the link does not work, is this possible at all? thanks
<a ui-sref="form.{{url}}" >Next Section</a>
and then in my controller, I set the url parameter this way
switch (option) {
case 'A': {
$scope.url = 'sectionA';
} break;
case 'B': {
$scope.url = 'sectionB';
} break;
}
Alternatively, I used directives to get it to work by generating the hyperlink with the desired ui-sref attribute according to the option selected on the select box (drop down).
Hhowever this means I have to re-create the link each time a different option is selected from the selectbox which causes an undesirable flickering effect. My question is this, is it possible to change the value of the ui-sref as I tried doing above by simpling changing the value of url in my controller or do I have to re-create the entire element using a directive each time a selection is made as I have done below? (just showing this for completeness)
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>
Upvotes: 83
Views: 75879
Reputation: 515
I found this solution the most appropriate:
.state('history', {
url: 'home',
controller: 'homeCtrl',
templateUrl: "home.html"
})
.state('settings', {
url: "/settings",
controller: 'settingsCtrl',
templateUrl: 'settings.html'
})
<button ui-sref="{{$ctrl.newProductLink()}}"</button>
ctrl.newProductLink = () => a > b ? 'home' : 'settings';
Upvotes: 0
Reputation: 300
<a ng-click="{{getLinkUrl({someParam: someValue})}}">Dynamic Link</a>
$scope.getLinkUrl = function(value){
$state.go('My.State',{someParam:value});
}
It returns an object
Upvotes: 1
Reputation: 1542
<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>
If someone only wants to dynamically set the $stateParams of ui-sref in Angularjs. Note: In inspect element it will still appear as "buy({myPairIndex:$index})" but $index will be fetched in that state.
Upvotes: 0
Reputation: 959
Take a look in this issue #2944.
The ui-sref
doesn't watch the state expression, you can use ui-state
and ui-state-params
passing the variable.
<a data-ui-state="selectedState.state" data-ui-state-params="{'myParam':aMyParam}">
Link to page {{selectedState.name}} with myParam = {{aMyParam}}
</a>
Also a quickly demo provided in the ticket.
Upvotes: 29
Reputation: 2087
After trying various solutions I found the problem in the angular.ui.router
code.
The problem comes from the fact that ui.router update
method is triggered with the ref.state
which means that it is not possible to update the value of the href
used when the element is clicked.
Here are 2 solutions to solve the problem:
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();
}
};
});
The HTML to use it is quite simple :
<a dynamic-sref="home.mystate"
dynamic-sref-params="{ param1 : scopeParam }">
Link
</a>
In angular.router.js your will find the directive $StateRefDirective
(line 4238 for version 0.3).
Change the directive code to :
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);
});
}
};
}
Upvotes: 2
Reputation: 104
The best approach is to make use of uiRouter's $state.go('stateName', {params})
on button's ng-click
directive. And disable the button if no option is selected.
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>
Controller
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 || {});
}
};
}
State
$stateProvider.state('wizard', {
url: '/wizard/:param1/:param2', // or '/wizard?param1¶m2'
templateUrl: 'wizard.html',
controller: 'Controller as ctrl'
});
Upvotes: 1
Reputation: 1534
For manage multiple dynamic params using ui-sref, here my solution :
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¶m2¶m3',
templateUrl: 'MyPage.html',
controller: 'MyCtrl'
});
Enjoy !
Upvotes: 0
Reputation: 623
Or just something like this:
<a ui-sref="{{ condition ? 'stateA' : 'stateB'}}">
Link
</a>
Upvotes: -1
Reputation: 2331
this is just working for me
in controller
$scope.createState = 'stateName';
in view
ui-sref="{{ createState }}"
Upvotes: 0
Reputation:
I managed to implement it this way (I'm using the controllerAs variant though - not via $scope).
Template
<button ui-sref="main({ i18n: '{{ ctrlAs.locale }}' })">Home</button>
Controller
var vm = this;
vm.locale = 'en'; // or whatever dynamic value you prepare
Also see the documentation to ui-sref
where you can pass params:
https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref
Upvotes: 2
Reputation: 123901
There is a working plunker. The most easier way seems to be to use combination of:
These together could be used as:
<a ng-href="{{$state.href(myStateName, myParams)}}">
So, (following this plunker) having states like these:
$stateProvider
.state('home', {
url: "/home",
...
})
.state('parent', {
url: "/parent?param",
...
})
.state('parent.child', {
url: "/child",
...
We can change these values to dynamically generate the href
<input ng-model="myStateName" />
<input ng-model="myParams.param" />
Check it in action here
ORIGINAL:
There is a working example how to achieve what we need. But not with dynamic ui-sref
.
As we can can check here: https://github.com/angular-ui/ui-router/issues/395
Q: [A]re dynamic ui-sref attributes not supported?
A: Correct.
But we can use different feature of ui-router
: [$state.go("statename")][5]
So, this could be the controller stuff:
$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);
};
And here is the HTML template:
<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>
The working example
NOTE: there is more up to date link to $state.go definition, but the deprecated one is a bit more clear to me
Upvotes: 61
Reputation: 4079
Came to answer that for good :)
Fortunately, you don't need to use a button for ng-click, or use a function inside an ng-href to achieve what you seek. Instead;
You can create a $scope
var in your controller and assign the ui-sref
string in it and use it in your view, as ui-sref
attribute.
Like this:
// 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>
That works perfectly for me.
Upvotes: 1
Reputation: 2344
Looks like this is possible to do after all.
A breadcrumb on GitHub by one of the ui-router authors led me to try the following:
<a ng-href="{{getLinkUrl()}}">Dynamic Link</a>
Then, in your controller:
$scope.getLinkUrl = function(){
return $state.href('state-name', {someParam: $scope.someValue});
};
Turns out, this works like a charm w/ changing scoped values and all. You can even make the 'state-name' string constant reference a scoped value and that will update the href in the view as well :-)
Upvotes: 72