Comments (12)
I did come up with a workaround... but it will only work for my situation since I plan on using my abstract states for each module in a similar fashion.
if (displayName !== false) {
var myRoute = currentState.abstract ? currentState.name + '.all ' + currentState.name : currentState.name;
breadcrumbs.push({
displayName: displayName,
route: myRoute
});
}
from angularutils.
Hi,
Good point - I didn't account for abstract states. Thanks for posting your work around, and I'll think about how a general solution could be implemented. If you come up with anything more general, feel free to post it or even do a pull request.
from angularutils.
Idea: Your solution involves re-assigning any breadcrumb of an abstract state to an alternative non-abstract (concrete?) state. In your case, you have a particular convention that makes it work out for you.
More generally, we could adapt that concept but make the redirection user-definable in the $state object. Something along the lines of this:
$stateProvider
.state('articles', {
url: '',
abstract: true,
template: '<ui-view/>',
resolve: {
loggedin: checkLoggedin
},
data: {
breadcrumbsProxy: 'articles.all'
}
})
.state('articles.all articles', {
url: '/articles',
templateUrl: 'articles/views/list.html',
data: {
displayName: 'Articles'
}
})
So we put a user-defined property called (for example, off the top of my head) breadcrumbsProxy
, which tells the directive which state to substitute for the abstract one. The name of the property could be specified as an attribute, much in the same way as is currently done with the displayname-property
.
When I get a bit of time I'll try to implement something along those lines.
from angularutils.
Michael that sounds like a great plan. I might have some time today to try and implement and test it with my project.
from angularutils.
Micheel, I am new to Angular and am having difficulty understanding how the code is retrieving the displayname property from the data object. I am trying to replicate that functionality for the breadcrumbProxy but am failing miserably. Can you point me in the right direction on the methodology or angularjs functionality to obtain the displayname from the data object in ui-router.
from angularutils.
Reading over the code myself, I even had to take a minute to figure out what was going on, so don't feel bad about not getting it!
Here's an explanation of what's going on:
function getDisplayName(currentState) {
var i;
var propertyReference;
var propertyArray;
var displayName;
if (!scope.displaynameProperty) {
// if the displayname-property attribute was not specified, default to the state's name
return currentState.name;
}
propertyArray = scope.displaynameProperty.split('.');
propertyReference = currentState;
for (i = 0; i < propertyArray.length; i ++) {
if (angular.isDefined(propertyReference[propertyArray[i]])) {
if (propertyReference[propertyArray[i]] === false) {
return false;
} else {
propertyReference = propertyReference[propertyArray[i]];
}
} else {
// if the specified property was not foundm default to the state's name
return currentState.name;
}
}
// use the $interpolate service to handle any bindings in the propertyReference string.
displayName = $interpolate(propertyReference)(currentState.locals.globals);
return displayName;
}
Let's assume the following setup:
.state('articles.article by id', {
url: '/articles/:articleId',
templateUrl: 'articles/views/view.html',
data: {
displayName: '{{ article.title }}'
}
})
<ui-breadcrumbs displayname-property="data.displayName"></ui-breadcrumbs>
- So, the
scope.displaynameProperty
comes from our attribute on the element, and is created on the scope for us by thescope: {displaynameProperty: '@'}
in our directive definition object. - We then split it into an array by ".", so in out case we get an array
['data', 'displayName']
. - The
for``loop then traverses down the current
$statedefinition object, checking if firstly the "data" property is defined on it. In our example the answer is "yes", and the value of it would be:
{ displayName : '{{ article.title }}' }`. We then set that result as the object to check in the next iteration. - In the next iteration of the loop, we check whether the next property from the array (
displayName
) is defined on the new object obtained from the first iteration. It is, and its value is the string `'{{ article.title }}'. - Now the loop is done, and we have successfully obtained the title for the breadcrumb. It could be a simple string, boolean false, or in this case, a special string in the syntax that Angular can iterpolate to find a dynamic value.
- To turn the string
'{{ article.title }}
into the actual value of the objectarticle.title
, we need to use the Angular service $interpolate. That service takes an Angular expression which we want to interpolate ({{ article.title }}
), and returns a function that then takes a context that is used to look up the value. By "context" is meant basically an object which is used to loop up the value to put into the{{ expression }}
. - In our case, that context is
currentState.locals.globals
- which is basically a pointer toresolve
property on our config object. So this allows it to look in that object, find thearticle
object, and return the value of its propertytitle
.
I hope I made that easy to follow. If you implement something similar, but for the "beadcrumbsProxy" idea, I'd suggest that a bunch of the logic from the above function could be shared by the new function to avoid repetition. Good luck!
from angularutils.
I implemented the fix suggested above - see e7adb82 (plus a few subsequent tweaks)
See the updated docs: https://github.com/michaelbromley/angularUtils/tree/master/src/directives/uiBreadcrumbs#working-with-abstract-states
The Plunker demo is also updated to demonstrate abstract states: http://plnkr.co/edit/bBgdxgB91Z6323HLWCzF?p=preview
from angularutils.
I got around to implementing your updates. I simplified the updateBreadcrumbsArray() a bit to get the expected output I wanted. I am not concerned about duplicate states and your demo doesn't seem to include the abstract state breadcrumb? Here is my function that I will be using. Thanks for your updates.
/**
* Start with the current state and traverse up the path to build the
* array of breadcrumbs that can be used in an ng-repeat in the template.
*/
function updateBreadcrumbsArray() {
var breadcrumbs = [];
var currentState = $state.$current;
while(currentState && currentState.name !== '') {
var workingState = getWorkingState(currentState);
var displayName = getDisplayName(currentState);
if (displayName !== false) {
breadcrumbs.push({
displayName: displayName,
route: workingState.name
});
}
currentState = currentState.parent;
}
breadcrumbs.reverse();
scope.breadcrumbs = breadcrumbs;
}
from angularutils.
Hi, okay - looks good. In the Plunker demo, the 'home.users' state is abstract, and it delegates to the 'home.user.list' state. Thus, when you are in the 'home.users.detail' state, clicking on 'Users' in the breadcrumbs will take you to 'users.list'.
from angularutils.
@michaelbromley sorry, yours works great, I was mistaken. Awesome job.
from angularutils.
Sorry for resurrecting this old thread, how can I do if I want to show the abstract state (done) but remove the href from it? making it plain text and non-clickable?
from angularutils.
@dannygoncalves Do do this quickly I would for the uibreadcrumb and create either a custom property or do a simple trick on the displayname.
For instance let's say you wanted to have your "Todo" breadcrumb to be only a link then instead of displayName: 'Todo' make it displayName: '[-]Todo' then update the following functions:
function stateAlreadyInBreadcrumbs(state, breadcrumbs) {
var i;
var alreadyUsed = false;
for(i = 0; i < breadcrumbs.length; i++) {
//check if route exists
if (breadcrumbs[i].route && (breadcrumbs[i].route === state.name)) {
alreadyUsed = true;
}
}
return alreadyUsed;
}
Inside updateBreadcrumbsArray..
//custom logic to not add the route and so it is text only
if (displayName.indexOf('[-]') !== -1) {
breadcrumbs.push({
displayName: displayName.replace('[-]','')
});
} else {
breadcrumbs.push({
displayName: displayName,
route: workingState.name
});
}
I tested this out and it works. You could add an additional property like textonlyProperty: '@' and check for that before you push the breadcrumb.
from angularutils.
Related Issues (20)
- Breadcrumbs could not handle multiple paths to access a particular state. HOT 1
- dirPagination: Pagination control is broken when using Multiple Pagination with Asynchronous Data HOT 1
- passing Empty Array to directive HOT 1
- dirPagination: 'dirPagination' is not in the npm registry.
- I am not able to use other custom directive with dirPaginate?
- async with filtering ?
- dirpaginate is not working inside a script type="text/ng-template" used for showing angular modals and the script is the child of another dirpaginate. Both dirpaginate is not working as expected.
- How to implement check all/uncheck all in dirPagination?
- How can I set the page number from the controller?
- Dirpagination in controller for thousand of data HOT 1
- How can I obtain the current index, and how can I set an existing page in specific? HOT 1
- How to exclude certain array items from total item count on current page HOT 1
- uiBreadcrumbs + ui-router V1 HOT 1
- dirPagination: repeating on object has least items on first page rather than last
- Displaying error
- dirPagination:hide() is not working in navigation
- Custom Pagination Button Style HOT 2
- Finally including this loading flag when pages are changed and query is returned API HOT 1
- dirPagination loading issue when total-items is more then 100000 even calling from server side HOT 2
- DirPagination for asynchronous call not working in angular js
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from angularutils.