I have an app with a directive called fightcard. In my app configuration, I'm using ui-router to change the state. This code works...
$stateProvider
.state('matches', {
url: '/matches',
template: '<fightcard matches="matches"></fightcard>'
})
But... I was wondering if there is a property on state like controller to simply pass in the directive instead of an html template. I'd like to do something like this:
$stateProvider
.state('matches', {
url: '/matches',
directive: 'fightcard',
directiveModels: ['matches']
})
The html template option isn't that terrible - it may actually be superior - just wondering if there is an alternative in more "angular way" or perhaps the html template is the preferred approach. Each match has sub views for the best of games... probably it's better to have the directives contained a simple html templates like so:
$stateProvider
.state('matches', {
url: '/matches',
templateUrl: 'partials/matches.html'
})
.state('matches.games', {
url: '/games',
templateUrl: 'partials/games.html'
})
matches.html template
<fightcard matches="matches"></fightcard>
games.html template
<h6>BEST OF 5 GAMES</h6>
<div ng-repeat="gameModel in games">
<game gamemodel="gameModel" class="centerText"></game>
</div>
Putting the directive in a template is THE way to use the directive in AngularJS.
If you wanted to get fancy, you could extend .state() using the .decorator() method of $stateProvider to parse your special config and create that template for you, but it would really be a round-about way to go about using the directive.
Related
Edit: Here is the complete code at Plunker. Though I can not c anything in execution but same code working at local. However gives a console error though
It all works perfect. But due to :id in /news/:id/, i am getting jquery/angular errors in console which can not be tracked anywhere in my code
I can not c What i am doing wrong.
Edit: Solved plunker https://plnkr.co/edit/FWcuBgGpVdMj3CroFrYJ
First of all you are trying to use ui-router but you're including ngRoute script in your plunker. Change it to
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.1/angular-ui-router.min.js"></script>
Then everything should work fine!
I suggest you a few changes...
1. Use ui-sref instead of href because it's much easier to define
ui-sref="post({id:1})" which turns into href="#/news/1"
If you would like to change url some day, then you will have to just change your route file, not each href.
$stateProvider
.state('post', {
url: "news/:id"
or
$stateProvider
.state('post', {
url: "archive/:id"
or
$stateProvider
.state('post', {
url: "whatever/:id"
2. Use abstract state
In your example it's a way better to define abstract state which holds header, content and footer - it's a typical use case.
ui-router
Abstract States
An abstract state can have child states but can not get activated
itself. An 'abstract' state is simply a state that can't be
transitioned to. It is activated implicitly when one of its
descendants are activated.
Some examples of how you might use an abstract state are:
To prepend a url to all child state urls. To insert a template with
its own ui-view(s) that its child states will populate. Optionally
assign a controller to the template. The controller must pair to a
template. Additionally, inherit $scope objects down to children, just
understand that this happens via the view hierarchy, not the state
hierarchy. To provide resolved dependencies via resolve for use by
child states. To provide inherited custom data via data for use by
child states or an event listener. To run an onEnter or onExit
function that may modify the application in someway. Any combination
of the above. Remember: Abstract states still need their own
for their children to plug into. So if you are using an
abstract state just to prepend a url, set resolves/data, or run an
onEnter/Exit function, then you'll additionally need to set template:
"".
Here's a plunker which shows how I would do it.
https://plnkr.co/edit/5FvJaelyxdl5MuALt5VY?p=preview
Hope it helps.
Look at the documentation for ui router named views,
You can use following syntax for using multiple views
$stateProvider
.state('state',{
url: '',
views: {
'header': {
templateUrl: 'views/header.html',
controller: 'headerCtrl'
},
'content': {
template: '<div ui-view=" "></div>', //<-- child templates loaded to here
},
'footer': {
templateUrl: 'views/footer.html',
controller: 'footerCtrl'
}
}
})
.state('state.post', {
url: 'news/:id/:KeyWords'
templateUrl: 'views/post.html' //<-- This goes into content's ui-view
});
I'm guessing you want to keep the header and footer and change content views.
You can achieve this by making this state as parent to all other states
suppose
.state('main',{
abstract: true,
views: {
'header': ... ,
'content': {
template: '<ui-view></ui-view>',
}
'footer': ...
}
})
then all the child views will load their views in the ,
ex: in main.child etc, your template will load in the content's <ui-view></ui-view> tag
If you need to use a custom template depending on keywords you can do the following:
.config(['$routeProvider',
function($routeProvider, $routeParams) {
$routeProvider
.when('/news/:id/:keyWords', {
template: '<div ng-include="url"></div>',
controller: "exampleController"
})
then in the exampleController
function($routeParams, $scope) {
$scope.url = $routeParams.keyWords;
}
I had my old code which worked just fine:
$urlRouterProvider.otherwise('/next');
$stateProvider
.state('next', {
url: '/next',
templateUrl: 'partials/next.html',
controller: function($scope, $state){
}
});
But then I got the brilliant idea to better organize my code, so I ended up with:
$urlRouterProvider.otherwise('/next');
$stateProvider
.state('app', {
abstract: true
})
.state('app.next', {
url: '/next',
templateUrl: 'partials/next.html',
controller: function($scope, $state){
}
});
Which is basically the same thing, but uses a dot notation, and an abstract state (not that it matters; even if I remove the abstract state, it still won't work).
The app does take me to /next, however the page is blank (only the base template is shown, not the content of /partials/next.html. The request for it is made, but it's simply not shown.
The relevant HTML code is just:
<div class="container" ui-view>
</div>
I was (somewhat) following the tutorial from https://scotch.io/tutorials/angular-routing-using-ui-router if that helps anything.
What am I doing wrong?
add in abstract state property:
template : '<div ui-view></div>'
It should looks like:
$urlRouterProvider.otherwise('/next');
$stateProvider
.state('app', {
abstract: true,
template : '<div ui-view></div>'
})
.state('app.next', {
url: '/next',
templateUrl: 'partials/next.html',
controller: function($scope, $state){
}
});
of course you can use templateUrl intead template. It is also very usefull to use layout templates in abstract state.
edit to answer comment:
Can I ask why this is necessary?
It is necessary, because angular run first abstract state, and its template. And then your actual state. But angular needs to know where put content of normal state template in parent abstract state template.
This template : '<div ui-view></div>' means that abstract state has simple template with only position of normal state template.
When using ui-router, I setup states like so:
$stateProvider
.state 'product',
url: '/catalog/product',
templateUrl: 'app/product/product.html',
The only problem is, I have my controller in a directive, not as a stand-alone controller service. So how do I tell ui-router to hit my directive instead of the template?
Otherwise I'm not sure how to bind the template scope to the controller defined in my directive.
If you insist on Directive, as a target for your state template, the way would be :
$stateProvider
.state 'product',
url: '/catalog/product',
template: '<div here-is-my-directive-with-all-its-standard-settings></div>',
NOTE: there does not have to be controller explicitly defined for view at all. Just the HTML template will be injected into position in parent
And the directive:
.directive('hereIsMyDirectiveWithAllItsStandardSettings', ...)
Other words, the UI-Router is handling states, and injecting the template. The template contains directive, which can do what was designed for... as expected...
Following this tutorial: https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views, i'm able to create an application with multiple views defined in a root template. I need to modify that scheme a bit by putting tabledata and graph to a child view called content. I want my views to look like that:
index.html
<body>
<div ui-view="header"></div>
<div ui-view="content"></div>
</body>
content.html
<div ui-view="tabledata"></div>
<div ui-view="graph"></div>
And my routes looks like that:
# ...
.state('videos',
url: '/videos'
templateUrl: 'content.html'
views:
'tabledata':
templateUrl: 'tabledata.html'
controller: '...'
'sidebar':
templateUrl: 'graph.html'
controller: '...'
)
However, when pointing my browser to /videos, tabledata.html and graph.html templates are not loaded to corresponding views. Everything works great though, if i'll put tabledata and graph views to index.html
I'm sure there is something really wrong with my code but i'm not able to figure out what exactly nor google anything up.
As far as I'm aware you can only have multiple ui-view's in multiple named views, i.e.when you explicitly declare a views property on your state definition. I'm not entirely sure what you're after, but if you would like to have control over where hese ui-views load their states then you can use an abstract state, from the link you provided:
Views override state's template properties
If you define a views object, your state's templateUrl, template and
templateProvider will be ignored. So in the case that you need a
parent layout of these views, you can define an abstract state that
contains a template, and a child state under the layout state that
contains the 'views' object.
This is what I suggest:
.state('videos',{
url: '/videos',
templateUrl: 'content.html',
abstract: true})
.state('videos.xyz',{
url: '/xyz',//you can leave this empty if you like
{
views:{
'tabledata':{
templateUrl: 'tabledata.html'
controller: '...'
},
'sidebar':{
templateUrl: 'graph.html'
controller: '...'
}
}
})
If you don't want that xyz appended to your url's, just pass in an empty string for the url property of the state videos.xyz. I use this approach all the time, let me know if it's what you're after.
I am using angular-ui-router to control my states in my AngularJS application. In one partial I use jquery-file-upload. The problem that I have is that when I use the example given by jquery-file-upload, is that it defines the controller in the template like this:
<!-- The file upload form used as target for the file upload widget -->
<form id="fileupload" action="//jquery-file-upload.appspot.com/" method="POST"
enctype="multipart/form-data" data-ng-app="demo"
data-ng-controller="DemoFileUploadController" data-file-upload="options"
data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
...
</form>
The form tag has data-ng-controller="DemoFileUploadController". In my controller this creates all the file upload methods needed (like $scope.submit() and $scope.queue)
The problem is that I define my controllers angular-ui-router style, like this in my app.js:
$stateProvider.state('upload', {
url: "/upload",
views: {
"upload": {
templateUrl: "app/partials/upload.html",
controller: 'DemoFileUploadController'
},
}
})
But this piece of code causes my file upload methods, not to be loaded (or bound) in my controller (there is no $scope.submit() and $scope.queue).
Is there a way I can use angular-ui-router and jquery-file-upload together?
My fix is to simply omit the controller when defining the state:
$stateProvider.state('upload', {
url: "/upload",
views: {
"upload": {
templateUrl: "app/partials/upload.html"
},
}
})
This way I assign the controller in my template (like in the example data-ng-controller="DemoFileUploadController"). I am still looking for a way to assign my controller via the stateProvider.