ui-sref not generating the href - angularjs

I'm not sure what is the mistake I'm doing here but the href is not generating. I have configured as per ui-router example but when I put the ui-sref in the ng-repeat its not generating the URL and also when I type the URL manually also its not working.
Even when I tied to set the value like data-ng-click="widget.open({widgetId: 1}) nothing happens.
Here is my code snippet.
Config:
.config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
function ($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/');
$locationProvider.html5Mode(true);
$stateProvider
.state('home', {
url: '/',
templateUrl: '/templates/home/home.html'
})
.state('widget', {
// With abstract set to true, that means this state can not be explicitly activated.
// It can only be implicitly activated by activating one of its children.
abstract: true,
// This abstract state will prepend '/widgets' onto the urls of all its children.
url: '/widget',
// Loading a template from a file. This is also a top level state,
// so this template file will be loaded and then inserted into the ui-view
// within index.html.
templateUrl: '/templates/widgets/index.html'
})
.state('widget.open', {
url: '/{widgetId:[\w+$]}', //matches [a-zA-Z_0-9]
templateUrl: '/templates/widgets/index.html'
})
.state('widget.create', {
url: '/{type:[a-zA-Z]}', // We can test enum list also
templateUrl: '/templates/widgets/index.html'
})
.state('mashup', {
// With abstract set to true, that means this state can not be explicitly activated.
// It can only be implicitly activated by activating one of its children.
abstract: true,
// This abstract state will prepend '/mashups' onto the urls of all its children.
url: '/mashup',
// Loading a template from a file. This is also a top level state,
// so this template file will be loaded and then inserted into the ui-view
// within index.html.
templateUrl: '/templates/mashups/index.html'
})
.state('mashup.open', {
url: '/{mashupId:[\w+$]}', //matches [a-zA-Z_0-9]
templateUrl: '/templates/mashups/index.html'
})
.state('mashup.create', {
url: '/{templateType:[a-zA-Z]}', // We can test enum list also
templateUrl: '/templates/mashups/index.html'
});
}])
Template:
<div class="panel panel-default widget-list">
<div class="panel-heading">
<h3 class="panel-title">My Widgets ({{widgets.length}})</h3>
</div>
<div class="panel-body hp-content">
<table class="table table-condensed table-bordered">
<tbody>
<tr data-ng-repeat="w in widgets">
<td class="hp-type">Icon</td>
<td>
<div class="row">
<div class="col-xs-12">
<a data-ui-sref="widget.open({widgetId: w.id })">{{::w.name}}</a>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-md-6">
{{::w.sourceId}}
</div>
<div class="col-xs-12 col-md-6">
{{::w.communityId}}
</div>
</div>
</td>
<td class="hp-actions">{{::w.access}}</td>
</tr>
</tbody>
</table>
</div>
<div class="panel-footer">Panel footer</div>
</div>
Could someone please point the mistake what I'm doing?
Thanks

There is no need to wrap the widget.id in curly braces:
data-ui-sref="widget.open({widgetId: {{widget.id}} })
Use:
data-ui-sref="widget.open({widgetId: widget.id })">

I think your problem is a naming issue. You are in a repeater that is widget in widgets, so when you do widget.open, I think its looking for a open function in the the widget object of the repeater and not the sub route 'widget.open'.

Related

Nested views with dot notation

can someone help me with this nested views in angular js.
I use this dot notation
$stateProvider
.state('contacts/:id', {
templateUrl: 'contacts.html',
controller: function($scope){
$scope.contacts = [{ name: 'Alice' }, { name: 'Bob' }];
}
})
.state('contacts/:id.list/:id', {
templateUrl: 'contacts.list.html'
});
function MainCtrl($state){
$state.transitionTo('contacts/:id.list/:id' );
}
In html I call state change also like this
<a ui-sref="contacts/{{value.id}}.list/{{value.id}}">get<\a>
But always I get
angular.js:12477 Error: Could not resolve 'contact/2.list/2' from state 'contact/:id'
Thnx
EDIT:
I make a change like #Maxim Shoustin answered. Now state changed, but in child navigation when I click on item, parent ui-view is full refreshed (child navigation and ui-view) not only child
now my state looks like this
.state('client', {
url: '/client/info/:itemID',
templateUrl: 'clientInfo.html',
controller: 'detailControllerClient as vm',
})
.state('client.detail', {
url: '/detail/:itemID',
templateUrl: 'itemInfoById.html',
controller: 'detailControllerClient as vm',
})
And html is here. (infoDisplay.html is parent view inside index.html. This ui-view in code bellow is child view (client.detail))
infoDisplay.html
<div class="new_nav col-lg-1 col-md-1 col-sm-2 col-xs-12">
<table class="table-hover">
<thead>
<tr>
<th>item ID</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="(key, value) in clientDetail">
<td><a ui-sref=".detail({'itemID': value.id})">{{value.id}}</a></td>
</tr>
</tbody>
</table>
</div>
<div ui-view></div>
<a ui-sref="contacts/{{value.id}}.list/{{value.id}}">get<\a>
You cannot use id.list with id because Angular determines like duplicated name id in pattern. But id_list is ok. For example
See ui-sref Docs
Where state is:
.state('contacts', {
url: '/contacts/:id_list/:id',
templateUrl: 'contacts.html'
})
and HTML:
<a ui-sref="contacts({'id_list': value.id, 'id': value.id})" >contacts</a>
Demo Plunker

reload controller when child state is changed - Angular UI Router

I'm new to Angular UI Router and am trying to create an application with nested views.
I've an index.html which hosts the 'header' state and the 'content' state. Within the content state, I have two nav bars representing a Global view and a Sub view. The Global View should open by default when the user opens the application.
However, at present, whenever I run the application, both Global and Sub view controllers are getting executed together(both views are getting loaded together).
What I wish instead is that only Global controller should get executed at first and then when the user clicks on Sub view, its controller should get executed. Following this, whenever the user switches between both the views, the controllers should reload.
I have been reading through Google and here but wasn't able to find the required solution. Please let me know if this is possible using ui-router. Thanks.
index.html
<html>
<body>
<div class="fluid-container">
<div ui-view="header"></div>
<div ui-view="content"></div>
</div>
</body>
</html>
content.html
<div class="row" style="background-color: #F9F9F8">
<div class="col-md-3"></div>
<div class="col-md-6">
<ul class="nav nav-pills nav-justified">
<li class="active"><a data-toggle="pill" href="#globalView">Global</a></li>
<li><a data-toggle="pill" href="#subView">Sub View</a></li>
</ul>
</div>
<div class="col-md-3"></div>
</div>
<div class="row">
<br>
<hr></hr>
<div class="tab-content">
<div id="globalView" class="tab-pane fade in active" ui-view="globalView"></div>
<div id="subAccountView" class="tab-pane fade" ui-view="subView"></div>
</div>
</div>
app.js
$urlRouterProvider.otherwise("/firstPage");
$urlRouterProvider.when('', '/firstPage');
$stateProvider
.state('home', {
url: '',
views: {
/** Find the views named in index.html and inject the named views**/
'header': {
templateUrl: 'views/header.html',
controller: 'headerController',
controllerAs: 'headerCtrl'
},
'content': {
templateUrl: 'views/content.html',
controller: 'contentController',
controllerAs: 'contentCtrl',
}
}
})
.state('home.summary', {
url: '/firstPage',
views: {
'globalView': {
templateUrl: "views/globalViewPage.html",
controller: "globalViewController",
controllerAs: "globalViewCtrl"
},
'subView': {
templateUrl: "views/subView.html",
controller: "subViewController",
controllerAs: "subViewCtrl"
}
}
});
I found the solution to my query by going through the tutorial provided by Weedoze in the comments. Below are the updated files.
index.html remains the same as above.
content.html
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-6">
<ul class="nav nav-pills nav-justified">
<li class="active"><a ui-sref=".globalView">Global</a></li>
<li><a ui-sref=".subView">Sub View</a></li>
</ul>
</div>
<div class="col-md-3"></div>
</div>
<div class="row">
<br>
<hr></hr>
<div class="tab-content">
<div class="tab-pane fade in active" ui-view></div>
</div>
</div>
A point to add here is that I was earlier having data-toggle="pill" in my anchor tag which was causing issues in navigating between the two child views. After digging further, I found that if this toggle is removed, the navigation works smoothly.
app.js
$urlRouterProvider.otherwise("/globalView");
$urlRouterProvider.when('', '/globalView');
$stateProvider
.state('home', {
url: '',
views: {
/** Find the views named in index.html and inject the named views**/
'header': {
templateUrl: 'views/header.html',
controller: 'headerController',
controllerAs: 'headerCtrl'
},
'content': {
templateUrl: 'views/content.html',
controller: 'contentController',
controllerAs: 'contentCtrl',
}
}
})
.state('home.globalView', {
templateUrl: "views/globalViewPage.html",
controller: "globalViewController",
controllerAs: "globalViewCtrl",
url: '/globalView'
})
.state('home.subView', {
templateUrl: "views/subView.html",
controller: "subViewController",
controllerAs: "subViewCtrl",
url: '/subView'
});
This code lets me switch between the two child views and whenever I toggle between the views, the controllers get reloaded.

How to use 1 ui-view if there are multiple ui-view elements with the same name?

I have a html structure like so,
<div class="content-wrapper">
<div class="content">
Click me
</div>
<div ui-view="content-view">Template goes here</div>
</div>
<div class="content-wrapper">
<div class="content">
Click me
</div>
<div ui-view="content-view">Template goes here</div>
</div>
Two content-wrapper divs with both a ui-view called content-view.
And my state config looks like this,
$stateProvider
.state('home', {
url: ''
})
$stateProvider
.state('content-view', {
url: '',
views: {
"content-view": {
template: '<div>Content</div>',
}
},
})
See it in action here > http://plnkr.co/edit/997KbH9beLLHClM0IKb9?p=preview
If a user clicks on one of two ui-sref elements both the ui-view 'content-view` elements get triggered and inject the template.
What I would like to see is that only the ui-view in the content-wrapper element that gets clicked gets triggered.
Hiding one or the other element wouldn't be a good solution, because then the views will still have to load all the data in them. So I think my best bet is to target the specific ui-view in the same content-wrapper element.
* Update *
I've updated my plunker > http://plnkr.co/edit/997KbH9beLLHClM0IKb9?p=preview
I create several rows with content divs in them. Each row has 1 ui-view element. If a user clicks on one of the links it places the template in each view. While I want to target the view that's inside the content wrapper that the user clicked on.
Instead of nested views you can use directive here as you have repeating same objects so nested views do not help you that much...
just define a directive which is only for templating (of course you can extend its feature by your needs)..,
app.directive('contentTemplate', function() {
return {
restrict: 'E',
template: '<div class="content-view">{{vm.movie.title || "No Movie"}} is selected</div>',
scope: {
movie: '='
},
controller: ContentTemplateController,
controllerAs: 'vm',
bindToController: true
}
})
function ContentTemplateController() {
// your directive controller if you need it
}
then bind your selected content with directive then whenever you change movie content of directive will be changed as well...
<div class="content-wrapper" ng-repeat="movieGroup in movieGroups">
<div class="content" ng-repeat="movie in movieGroup">
<button ng-click="movieGroup.selectedMovie = movie;">{{ movie.title }}</button>
</div>
<content-template movie="movieGroup.selectedMovie"></content-template>
</div>
Creating independent ui-view states with the same name is simply not possible with the current model that ui-router has provided. The closest possible implementation is probably ui-router-extras's sticky module. You can create multiple independent(sticky) states by taking advantage of multiple named views in a state.
DEMO
Javascript
app = angular.module('myApp', [
'ui.router',
'ct.ui.router.extras'
]);
app.controller('mainCtrl', ['$scope',
function($scope){}
])
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('main', {
url: '/'
})
.state('main.sub1', {
sticky: true,
views: {
'sub1#': {
template: 'sub1<ui-view />'
}
}
})
.state('main.sub1.part1', {
template: '.part1'
})
.state('main.sub2', {
sticky: true,
views: {
'sub2#': {
template: 'sub2<ui-view />'
}
}
})
.state('main.sub2.part1', {
template: '.part1'
});
});
HTML
<div class="content-wrapper">
<div class="content">
<a ui-sref="main.sub1">main.sub1</a> |
<a ui-sref="main.sub1.part1">main.sub1.part1</a>
</div>
<div ui-view="sub1">Template goes here</div>
</div>
<div class="content-wrapper">
<div class="content">
<a ui-sref="main.sub2">main.sub2</a> |
<a ui-sref="main.sub2.part1">main.sub2.part1</a>
</div>
<div ui-view="sub2">Template goes here</div>
</div>

How to use ng-class on a top level container when using nested views

I am trying to import a toggleable sidebar and trying to use nested views so that I can dynamically change content of each section individually.
My app has 3 main components
1) a sidebar
2) a header
3) a content area
The problem I have is that in the original project everything is inside a single controller and there is an ng-class that toggles the sidebar which is can be toggled on clicking, but I am unable to reproduce it in the my application.
Here is what my index.html code looks like at the moment
<div id="page-wrapper" ng-class="{'open': toggle}" ng-cloak>
<div id="sidebar-wrapper" ui-view="sidebar">
</div>
<div id="content-wrapper">
<div class="page-content">
<!-- Header Bar -->
<div class="row header" ui-view="header">
</div>
<!-- Header Bar -->
<div ui-view="content" ></div>
</div>
</div>
</div>
And my route config.
.state('home', {
url: '/',
views: {
'content': {
templateUrl: 'home.html',
controller: 'HomeCtrl as home'
},
'sidebar': {
controller: 'SidebarCtrl as sidebar',
templateUrl: 'sidebar.html'
},
'header': {
controller: 'HeaderCtrl as header',
templateUrl: 'header.html'
}
}
});
I am confused on how I can toggle the sidebar using ng-class as I cannot place it inside any other template for it to work.
My previous comments as an answer:
in your html:
<div id="page-wrapper" ng-controller="myctrl" ng-class="{'open': toggle}" ng-cloak>
...
</div>
in your script file:
.controller('myctrl',[ '$scope', function($scope){
$scope.toggle = true; // open initially
}]);

View is loaded twice using angular ui router

I am having a problem in my view. The view is loaded twice and I have no idea what's going on.
What I have done in my index file is this:
<body class="ng-cloak">
<!--Menus-->
<div class="container-fluid">
<div data-ng-controller="HomeCtrl" class="row">
<!--Here is the ui view directive-->
<div class="col col-md-12" data-ui-view ></div>
</div>
</div>
<!--script files here-->
</body>
On the routes file I have these. The problem only occurs when i visit the contact.inner page
$stateProvider
.state('home', {
url: '/',
templateUrl: 'partials/home.html'
})
.state('contact', {
url: '/contact',
templateUrl: 'partials/contact.html'
})
.state('contact.inner', {
url: '/inner',
templateUrl: 'partials/inner.html'
});

Resources