Not getting breadcrumb name in view - angularjs

<td><i class="dataentry-breadcrumb" /></td>
<!-- {{breadcrumb.length}} {{breadcrumb[0].nodeName}} -->
<td ng-repeat="breadCrumbObj in breadcrumb">
<i class="dataentry-breadcrumbArrow" />
<a class="dataentry-breadcrumbElement" href='#'
title="{{breadCrumbObj.nodeName}}"
ng-click=updateBreadCrumb(breadCrumbObj.level)>{{breadCrumbObj.nodeName}}</a>
</td>
In the above code, nodeName in anchor tag is not getting display in UI. But it is present in the array.I tried to print it and commented. It was showing nodeName. But not in anchor tag. Please anyone help me...

I will show how I did it, as it seemed more logical and more apstracted so you can have better control of the views you are displaying.
First of all, you place it in the basic html file where it is displayed. Something like this:
<div ncy-breadcrumb></div>
Now this allows you to create a independent element for a breadcrumb, so now we have basically a custom directive for it, and within breadcrumb.html you model it with something like this, again mostly html.
<div class="breadcrumb">
<span ng-repeat="step in steps | limitTo:(steps.length-1)">
<a class="btn btn-tab" href="{{step.ncyBreadcrumbLink}}">{{step.ncyBreadcrumbLabel}}</a>
<span class="btn btn-tab btn-tab-divider">></span>
</span>
<span ng-repeat="step in steps | limitTo:-1">
<span class="btn btn-tab btn-current">{{step.ncyBreadcrumbLabel}}</span>
</span>
</div>
So now that you have some layout in the breadcrumb, you call it from the state controller where you control the views of your app. You first set it up as dependency.
'$breadcrumbProvider', function($breadcrumbProvider, ..) {
configure it within the function
// configure breadcrump
$breadcrumbProvider.setOptions({
templateUrl: 'scripts/nav/breadcrump.html'
});
and than all there is left to do, name how you call it depending on where you are in the app. Like this:
.state('root.vacancy', {
url: '/vacancies/:id',
shouldHighlight: 'home',
views: {
'main-content#root': {
templateUrl: 'scripts/vacancies/vacancy.html',
controller: 'VacancyController',
resolve: {
vacancy: function(vacancyService, $stateParams) {
return vacancyService.getVacancy($stateParams.id);
}
}
}
},
ncyBreadcrumb: {
label: "{{newProfile.vacancyTitle}}",
parent: 'root.home'
}
})
You set the state for routing for each state you have in the app. This way a solid amount of modular architecture is incorporated, and your breadcrumb is superbly independent :)
Hope it helps.

Related

Lazyload to multiple views in ui-router

A few months ago I've be created the topic: Try to render two templates in same View (Ui-Router), where I asked about how to render multiple views in the same page. My objective with this was created a web app as an desktop one, with views to minimize, maximize, close and stuff like that.
Well, my app is ready but I'm getting a problem, when I up my app to the production some computers are taking a long time to render all the Views. In the image bellow we can se a lot of requisitions that server take to return my templatesURL's.
There is a way to avoid this ? I was looking for an lazy load to templateURL but I Didn't find any. :(
This plunkr was the approach what I used. I have only one state for all my Views (My current app.config has 103 Views):
routerApp.config(function($stateProvider) {
$stateProvider.state('mainState', {
views: {
'CompanyView': {
templateUrl: 'Company.html'
},
'PeopleView': {
templateUrl: 'People.html'
},
.....
....
}
})
});
Introduction
The way you approached the solution is the cause of the problem you're facing, because you have too many views for a single state, it'll end up having to load all of them in order to set that state, so every time you access your state, ui-router has to load every template in order to set the views. It might not cause problem for a few number of templates, but, for larger numbers like yours it is definitely an issue.
Ng-Templates
You can try to cache your templates in your page using <script type="text/ng-template"... in order to prevent the loading time, it's a good practice by the way. Usually it's part of the production build optimization, load all templates in the template cache, so that the application load time decreases significantly provided that you don't have to wait for an http call to load a page. It will indeed increase the performance in your case, but I don't have a benchmark that ensure if it'd be enough for your scenario.
Component Based Solution
Anyhow, you can always implement interface components to behave the way you want, optimized in such a way that it doesn't have to load one hundred templates to show a single panel for the user.
My suggestion is, instead of using ui-router, use a component based solution, create a directive component to hold the panel content of each window and its behavior; and use a controller to manage the state of opened and closed panels, holding and managing each opened panel in a list and so on. For example:
<nav>
<button ng-click="openPanel({title: 'My Panel Title', templateUrl: 'myPanel.html'>">
Open myPanel
</button>
<nav>
<main>
<panel ng-repeat="panel in openedPanels"></panel>
</main>
The following snippet implements this approach using bootstrap 4 css, each panel is a bootstrap card, and it has a list of panels it can open and on click of a nav list it adds the respective panel to the opened panels list where angularjs can render it on the html using ng-repeat. This way, only the opened window will be rendered, therefore, only the opened window template will be loaded.
Disclaimer: This is a very simple example implemented not using the best practices available out there. If you intend to use this approach you should implement it based on your application to fit better the needs of your architecture, this one is not a complete functional component, it's just an example for the sake of the demonstration.
angular.module('app', [])
.controller('PanelsCtrl', function($scope) {
// available windows to be opened
$scope.panels = [
{ title: 'Window 1', templateUrl: 'window1.html' },
{ title: 'Window 2', templateUrl: 'window2.html' }];
// all currently opened panels
$scope.openedPanels = [];
// opens a panel (a.k.a, adds a panel
// to the opened panels list)
$scope.openPanel = function(panel) {
if ($scope.openedPanels.indexOf(panel) === -1)
$scope.openedPanels.push(panel);
};
// close a panel (a.k.a, removes a panel
// from the opened panels list)
$scope.onClosePanel = function(panel) {
$scope.openedPanels.splice($scope.openedPanels.indexOf(panel), 1);
};
})
.directive('window', function($templateRequest, $templateCache, $compile) {
return {
restrict: 'E',
scope: {
panel: '=',
onClosePanel: '&'
},
template: `
<div class="card">
<h4 class="card-header">
<span>{{ panel.title }}</span>
<button
ng-click="onClosePanel(panel)"
type="button"
class="close"
data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</h4>
<div class="card-body">
<ng-include src="panel.templateUrl"></ng-include>
</div>
</div>
`
}
})
// example controlelr to be used with ng-controller
.controller('Window1Ctrl', function($scope) {
$scope.window1Prop = 'This is a property from Window1Ctrl'
})
#import 'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css'
<div ng-app="app">
<div class="container" ng-controller="PanelsCtrl">
<div class="row">
<div class="col-sm-3">
<ul class="nav flex-column">
<li class="nav-item" ng-repeat="panel in panels">
<a class="nav-link active" href="#" ng-click="openPanel(panel)">
{{ panel.title }}
</a>
</li>
</ul>
</div>
<div class="col-sm-9">
<window ng-repeat="panel in openedPanels" panel="panel" on-close-panel="onClosePanel(panel)">
</window>
</div>
</div>
</div>
<!-- NG-TEMPLATES -->
<script type="text/ng-template" id="window1.html">
<div ng-controller="Window1Ctrl">
<b>{{panel.title}}</b>
<h5>window1Prop: {{ window1Prop }}</p>
</div>
</script>
<script type="text/ng-template" id="window2.html">
<em>{{panel.title}}</em>
</script>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.js"></script>

ng-repeat and polymorphic directive

I'm wondering if there is a way to build a custom Element directive to use with ng-repeat in this way:
<div class="list">
<my-custom-directive class="item item-icon-right" ng-repeat="a in concepts">
<p>{{::a.label}}</p>
<i class="icon ion-forward muted"></i>
</my-custom-directive>
</div>
my-custom-directive should compile itself in an anchor if a.href exists, in a paragraph if it doesn't.
The problem basically is merely design: I have some items which doesn't have an href, but they should still be in the list. In Ionic1 it looks like I can do a div list or an a list, but not mixing up without breaking the list design..
Sure you can. Something like this:
<my-custom-dir ng-repeat="a in concepts"></my-custom-dir>
where, directive is like,
app.directive('myCustomDir', function() {
return {
restrict: 'E',
templateUrl: 'custom.html'
}
})
And, the custom.html template,
<p ng-hide="a.href">{{::a.label}}</p>
<a ng-href="{{a.href}}" ng-show="a.href">{{::a.label}}</a>
<i class="icon ion-forward muted"></i>
Also, I kept the $scope.concepts to have dummy object as follows,
$scope.concepts = [{
href: 'eample.com',
label: 'example'
}, {
label: 'example1'
}, {
href: 'eample2.com',
label: 'example2'
}]
working example
Although, I think you should be able to have a div.item with ng-repeat inside your .list. And in the div.item you should be able to have whatever you want (not sure how ionic1 deals with that though)

angular-ui-router: add css class if state matched

simple wiki
I'd like to show an edit button in the navbar is state == 'page'
v0.2.10
.state('page',{
url: "/wiki/{ns:[0-9a-zA-Z\-/_]+}/{wp:[0-9a-zA-Z\-/_]+}",
templateUrl: "views/wiki/view.html",
controller: "PageController"
})
I tried
<li ng-show="$state.$current.name == 'page'"><button type="button" class="btn btn-default navbar-btn">Edit</button></li>
and
<a ng-class="{hidden: $state.$current.name == 'page'}" class="btn navbar-btn btn-primary" ui-sref="edit">Edit</a>
even
$state.includes('page')
and
$state.is('page')
I do this all the time in projects. The trick is to add a method on scope to check states.
$scope.is = function(name){
return $state.is(name);
}
$scope.includes = function(name){
return $state.includes(name);
}
Html:
<li ng-show="is('page')">
<a ng-class="{hidden: is('page')}">...</a>
I generally put those on root scope, but they are extremely useful. Another thing to look into is using the ui-sref-active directives. They are very good when you are creating links to states, and also want to auto-magically add a class when that state is active.
I think the best way to do this is to use ui-sref-active directive. The usage is pretty straight forward:
<a ui-sref-active="active" ui-sref="login">Login</a>
So when you are on login page it will automatically add class active to your a tag.
Another way you can accomplish this with they way you've written it.
app.run(function($rootScope, $state) {
$rootScope.$state = $state;
});
This will make the state available in all views so you could do something like
$state.current.name == 'page'

AngularJS UI Router : Loading Sibling Views on Demand

I have been searching how to implement sibling views on demand. What I have achieved so far is loading them together. Below is the sample which i am working on.
When clicked on any item on the left, the right hand ui-view in blue is loaded, which has contains details of the item and also two named views. Item Configuration and Item Price are two anchor tags which when clicked will display the respective view.
I hope the description is helpful and if someone can provide a solution that would be helpful.
View is written for the red border as follows (HTCOne.cshtml)
<div class="row">
<div class="col-md-5 ">
<h1>Meet HTC One M8</h1>
</div>
<div class="col-md-5 ">
<a ui-sref="SmartPhone.HTCOne.Config">See Configuration</a>
</div>
<div class="col-md-2">
<a ui-sref="SmartPhone.HTCOne.Price">Price Range</a>
</div>
</div>
<div class="row">
<div class="col-md-5 ">
<img src="~/Content/Images/HTCM8.JPG" />
</div>
<div class="col-md-5 ">
<div ui-view="Config" autoscroll=" false"></div>
</div>
<div class="col-md-2 ">
<div ui-view="Price" autoscroll="false"></div>
</div>
</div>
UI-router code
.state('SmartPhone.HTCOne', {
url: '/HTCOne',
templateUrl: '/home/HTCOne'
})
.state('SmartPhone.HTCOne.Price', {
views: {
'Price': {
template: '<B>Ranges form $ - $</B>'
},
'Config': {
templateUrl: '/home/HTCOneConfig'
}
}
})
Another version of UI-Router - If I you use two different states for the two named views, I get only one view displayed at a time , like behaving mutually exculsive way
.state('SmartPhone.HTCOne', {
url: '/HTCOne',
templateUrl: '/home/HTCOne'
})
.state('SmartPhone.HTCOne.Price', {
views: {
'Price': {
template: '<B>Ranges form $ - $</B>'
}
}
})
.state('SmartPhone.HTCOne.Config', {
views: {
'Config': {
templateUrl: '/home/HTCOneConfig'
}
}
})
UI router is essentially a state machine.
You can only be in one state at any particular time(with exception of parent states which are active when children states are active).
In your situation dont you want both price and config visible at some point? If thats the case, using states is not appropriate. You should use ng-includes instead.
Update:
Did you actually place the named ui-views where your black boxes are for "Some Configuration" and for "Item Price", i.e.
<div ui-view="Price"></div>
<div ui-view="Config"></div>

AngularJS UI Bootstrap Tabs that support routing

I would like to use AngularJS UI Bootstrap Tabs in my project, but I need it to support routing.
For example:
Tab URL
--------------------
Jobs /jobs
Invoices /invoices
Payments /payments
As far as I can tell from the source code, the current tabs and pane directives doesn't support routing.
What would be the best way to add routing?
To add routing you typically use an ng-view directive. I'm not sure it's easy enough to modify angular UI to support what you're looking for, but here's a plunker showing roughly what i think you're looking for (it's not necessarily the best way of doing it - hopefully someone can give you a better solution or improve on this)
Use data-target="#tab1". Worked for me
This answer really helped me http://odetocode.com/blogs/scott/archive/2014/04/14/deep-linking-a-tabbed-ui-with-angularjs.aspx (very simple but powerful solution)
I also have this requirement and I'm doing something similar to the answer provided by Chris, but I'm also using AngularUI router, because ngRouter does not support nested views and it is possible you'll have the tabs content view inside another view (I did) and that won't work with ng-view.
you could pass your own custom key value pairs in the route definition and achieve this.
here's a good example:
http://www.bennadel.com/blog/2420-Mapping-AngularJS-Routes-Onto-URL-Parameters-And-Client-Side-Events.htm
Agree with the use of UI-Router which tracks states and works great with nested views. Speaking particularly of your Bootstrap tabs issue there is a great implementation that leverages UI Router: UI-Router Tabs
If you have a route called settings and you want to have tabs in that settings page something like this works.
<div class="right-side" align="center">
<div class="settings-body">
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" href="#!/settings#private_email">Private email</a></li>
<li><a data-toggle="tab" href="#!/settings#signature">Signature</a></li>
<li><a data-toggle="tab" href="#menu2">Menu 2</a></li>
</ul>
<div class="tab-content">
<div id="private_email" class="tab-pane fade in active">
<div class="row" ng-controller="SettingsController">
<div>
<button class="btn btn-primary" ng-click="activatePrivateEmail()">Activate email</button>
<button class="btn btn-danger">Deactivate email</button>
</div>
</div>
</div>
<div id="signature" class="tab-pane fade">
<textarea ui-tinymce="tinymceOptions" ng-model="signature"></textarea>
<div class="send-btn">
<button name="send" ng-click="" class="btn btn-primary">Save signature</button>
</div>
</div>
<div id="menu2" class="tab-pane fade">
<h3>Menu 2</h3>
<p>Some content in menu 2.</p>
</div>
</div>
</div>
</div>
I got tabs with routing working the following way.
It's able to do everything you want from dynamic tabs, and it's actually very simple.
Tabs with a ui-view, so it can dynamically load templates,
Update routing in URL
Set history state
When directly navigating to a route with a tabbed view, the correct tab is marked as active.
Define the tabs with a parameter in your router
.state('app.tabs', {
url : '/tabs',
template : template/tabs.html,
})
.state('app.tabs.tab1', {
url : '/tab1',
templateUrl : 'template/tab1.html',
params : {
tab : 'tab1'
}
})
.state('app.visitors.browser.analytics', {
url : '/tab1',
templateUrl : 'template/tab2.html',
params : {
tab : 'tab2'
}
})
The tabs template (tabs.html) is
<div ng-controller="TabCtrl as $tabs">
<uib-tabset active="$tabs.activeTab">
<uib-tab heading="This is tab 1" index="'tab1'" ui-sref="app.tabs.tab1"></uib-tab>
<uib-tab heading="This is tab 2" index="'tab2'" ui-sref="app.tabs.tab2"></uib-tab>
</uib-tabset>
<div ui-view></div>
</div>
Which is paired with a very simple controller for getting the current active tab:
app.controller('TabCtrl', function($stateParams) {
this.activeTab = $stateParams.tab;
})
just a small add to accepted answer:
i needed to keep the current tab at page refresh so i used a switch like this:
$scope.tabs = [
{ link : '#/furnizori', label : 'Furnizori' },
{ link : '#/total', label : 'Total' },
{ link : '#/clienti', label : 'Clienti' },
{ link : '#/centralizator', label : 'Centralizator' },
{ link : '#/optiuni', label : 'Optiuni' }
];
switch ($location.path()) {
case '/furnizori':
$scope.selectedTab = $scope.tabs[0];
break;
case '/total':
$scope.selectedTab = $scope.tabs[1];
break;
case '/clienti':
$scope.selectedTab = $scope.tabs[2];
break;
case '/centralizator':
$scope.selectedTab = $scope.tabs[3];
break;
case '/optiuni':
$scope.selectedTab = $scope.tabs[4];
break;
default:
$scope.selectedTab = $scope.tabs[0];
break;
}
This aught to be able to do what you want:
https://github.com/angular-ui/ui-router

Resources