I have the following configuration:
$routeProvider
.when('/cars', { templateUrl: 'app/cars/index.html', controller: 'CarsCtrl', reloadOnSearch: false })
.when('/bikes', { templateUrl: 'app/bikes/index.html', controller: 'BikesCtrl', reloadOnSearch: false });
and somewhere in my root index.html there is a:
Cars
Bikes
<div ng-view></div>
Now, I want both views loaded and generated in the DOM at the same time, and show one of them depending on the route/URL.
Something like the following (not actual working code, just to give you an idea).
app.js:
$routeProvider
.when('/cars', { controller: 'CarsCtrl', reloadOnSearch: false })
.when('/bikes', { controller: 'BikesCtrl', reloadOnSearch: false });
root index.html:
Cars
Bikes
<div ng-include="'app/cars/index.html'" ng-show="carsVisible"></div>
<div ng-include="'app/bikes/index.html'" ng-show="bikesVisible"></div>
UPDATE: I know that ng-view kind of does this, but the difference, if subtle, exists. I want the html of each view to be generated once and stay in the DOM at all times.
I created a single RouteCtrl to load all of your views via ng-include. ng-view is not used. I inlined the templates. The templates could contain their own ng-controller directives to pull in specific controllers.
<body ng-controller="RouteCtrl">
Cars
Bikes
<div ng-controller="RouteCtrl">
<div ng-include="'/cars.html'" ng-show="carsVisible"></div>
<div ng-include="'/bikes.html'" ng-show="bikesVisible"></div>
</div>
<script type="text/ng-template" id="/cars.html">
Cars template.
</script>
<script type="text/ng-template" id="/bikes.html">
Bikes template.
</script>
$routeProvider is still configured, but no template or controller is specified, causing the RouteCtrl to always be active. That controller listens for the $routeChangeSuccess event and manipulates the ng-show properties accordingly.
app.config(function($routeProvider) {
$routeProvider
.when('/cars', {} )
.when('/bikes', {})
});
app.controller('RouteCtrl', function($scope, $route, $location) {
$scope.$on('$routeChangeSuccess', function() {
var path = $location.path();
console.log(path);
$scope.carsVisible = false;
$scope.bikesVisible = false;
if(path === '/cars') {
$scope.carsVisible = true;
} else if(path === '/bikes') {
$scope.bikesVisible = true;
}
});
});
Plunker
The idea for this solution is from #Andy.
I found another way, which I think is the simplest, quickest and most manageable:
How to set bootstrap navbar active class with Angular JS?
Which is:
Use ng-controller to run a single controller outside of the ng-view:
<div class="collapse navbar-collapse" ng-controller="HeaderController">
<ul class="nav navbar-nav">
<li ng-class="{ active: isActive('/')}">Home</li>
<li ng-class="{ active: isActive('/dogs')}">Dogs</li>
<li ng-class="{ active: isActive('/cats')}">Cats</li>
</ul>
</div>
<div ng-view></div>
and include in controllers.js:
function HeaderController($scope, $location)
{
$scope.isActive = function (viewLocation) {
return viewLocation === $location.path();
};
}
Instead of using ng-include, you should use ng-view;
This will display the content of either app/cars/index.html or app/bikes/index.html
Cars
Bikes
<div ng-view></div>
See the Template section from http://docs.angularjs.org/tutorial/step_07
Use a service with a show directive:
<div ng-show="myService.isActive('/')">Show this when at default route</div>
<div ng-show="myService.isActive('/cars')">Show this when at cars</div>
Service:
myApp.factory('MyService',
function ($location) {
return {
isActive: function (path) {
return (($location.path() == path));
}
}
}
);
App.js:
// this is run after angular is instantiated and bootstrapped
myApp.run(function ($rootScope, myService) {
$rootScope.breadcrumbService = MyService;
});
Related
My landing page component's controller doesn't retrieve any data when the app initially loads or when I reload from the landing page. I keep getting undefined for my variables when I have verified there is data.
If I click on the #/index link, the data loads fine and my variable logs to the console. Any idea why this happens to only the initial load of the webpage and when I reload it on the landing?
Edit: Added the appUser value that I am trying to log along with the app's main controller. Essentially, I run a service via appStore to retrieve user details. I then set my appUser value. I have confirmed the appStore service works.
It seems like the MainLandingCtrl runs before the AppCtrl
app.module.js:
angular.module('dup', ['ngRoute', 'mainLanding', 'unauthorized']);
app.value.js
angular.module('dup')
.value('appUser', {
fup: undefined
});
app.controller.js
angular.module('dup')
.controller('AppCtrl', ['appStore', 'appUser', '$log', function(appStore, appUser, $log) {
var rcAppTemp = this;
// User authorization
appStore.authorizedUser()
.then(function(response) {
rcAppTemp.userDetails = response.data;
appUser.fup = rcAppTemp.userDetails.fup;
}, function(error) {
$log.log('error');
});
}]);
app.config.js:
angular.module('dup')
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
// Main page
.when('/', {
template: '<main-landing></main-landing>'
})
.when('/unauthorized', {
template: '<unauthorized></unauthorized>'
})
.otherwise({
redirectTo: '/'
});
}]);
main-landing.controller.js:
angular.module('mainLanding')
.controller('MainLandingCtrl', ['appUser', '$log', function(appUser, $log) {
var mn = this;
mn.fup = appUser.fup;
$log.log(mn.fup);
}]);
main-landing.component.js
angular.module('mainLanding')
.component('mainLanding', {
bindings: {
},
templateUrl: 'components/main-landing/main-landing.template.html',
controller: 'MainLandingCtrl'
});
index.html:
<body ng-app="dup">
<div ng-controller="AppCtrl as app">
<!-- navigation bar (excluded for brevity) -->
</div>
<div ng-view></div>
</body>
main-landing.template.html
<div class="row">
<div class="small-12 medium-4 medium-offset-4 large-4 large-offset-4 columns">
<div title="Home">
<h5>Dup</h5>
<ul>
<li><strong>Index</strong></li>
<li ng-show="$ctrl.fup><strong>Trouble</strong></li>
</ul>
</div>
</div>
</div>
I am using ui-router for my routing, and am going to be using nested scopes and therefore want to be using the 'controller as' syntax. However, I can't work out the correct syntax / combinations to access the controller object properties in my view.
app.js (sets up routing)
(function() {
angular
.module('ICP_App', ['ui.router', 'satellizer', 'ngMaterial', 'ngMessages', 'xeditable'])
.config(function($stateProvider, $urlRouterProvider, $authProvider) {
$urlRouterProvider.otherwise('dashboard');
$stateProvider
.state('clients', {
url: '/clients',
templateUrl: '../partials/clients-index.html',
controller: 'ClientsController as ClientsCtrl'
})
// more routes here...
})();
ClientsController.js
(function() {
angular.module('ICP_App')
.controller('ClientsController', function($http) {
$http.get('http://api.icp.sic.com/clients')
.success(function(clients) {
var vm = this;
vm.clients = clients.data;
console.log(vm.clients);
})
.error(function(error) {
// handle here
})
});
})();
index.html
<body ng-app="ICP_App" ng-cloak>
<!-- sidebar, header etc -->
<div ui-view></div> <!-- pull in view -->
</body>
Finally, clients-index.html partial
<div class="content">
<div class="pane" ng-repeat="client in clients">
{{ client.name }}
</div>
</div>
I have also tried client in vm.clients, to no avail.
Is there a problem with my controller as syntax? As I am using controller as in my ui-router code, yet not again when creating my controller. If I use controller as again in my controller, it errors (Argument ClientsController is not a).
I should point out that console logging vm.clients does give me the data in the console, I just can't seem to access it in my view.
Thanks in advance.
Modify your ClientsController as follow
(function() {
angular.module('ICP_App')
.controller('ClientsController', function($http) {
var vm=this;
$http.get('http://api.icp.sic.com/clients')
.success(function(clients) {
vm.clients = clients.data;
console.log(vm.clients);
})
.error(function(error) {
// handle here
})
}); })();
Modify client-index.html as following
<div class="content">
<div class="pane" ng-repeat="client in ClientsCtrl.clients">
{{ client.name }}
</div>
Below link will help you to understand controller as syntax more deeply
https://toddmotto.com/digging-into-angulars-controller-as-syntax/
How can I add a class outside of the scope? As you can see here I want to add a class to header, main and footer
<header class="{{pageClass}}"></header>
<main class="{{pageClass}}" ng-view></main>
<footer class="{{pageClass}}"></footer>
This is my routing and the controller:
app.config(function($routeProvider) {
$routeProvider
.when('/chapter/:title', {
templateUrl: 'article.html',
controller: 'article'
})
.when('/suche', {
templateUrl: 'search.html',
controller: 'search'
})
.otherwise({
redirectTo: '/search'
});
});
app.controller('article', function($scope) {
$scope.pageClass = 'normal';
});
app.controller('search', function($scope) {
$scope.pageClass = 'small';
});
Now I want to add the class 'normal' when the user has opened an article. If the user goes to the search-page, another class (i.e. 'small') should be added.
So there are always set a class to every three tags (header, main and footer). The difference is just which kind of routing is been used.
Hope I could explain what I try to achieve.
You need to put the class on a parent scope or on $rootScope if no other parent scope exists.
The scope of ng-view is only available to the tag itself and its children.
Change your controllers to:
app.controller('article', function( $rootScope ) {
$rootScope.pageClass = 'normal';
});
app.controller('search', function( $rootScope ) {
$rootScope .pageClass = 'small';
});
There would be an parent controller to your body tag that will have $scope.parent = {}; object which will have that className.
Note
I've use $scope.parent = {}; because child controller can directly
access className by doing $scope.parent.className Using Javascript
prototypal inheritance here
Markup
<body ng-controller="parent">
<header ng-class="parent.className"></header>
<main ng-class="parent.className" ng-view></main>
<footer ng-class="parent.className"></footer>
</body>
Code
app.controller('parent', function($scope) {
$scope.parent = {};
});
app.controller('search', function($scope) {
$scope.parent.pageClass = 'small';
});
app.controller('article', function($scope,) {
$scope.parent.pageClass = 'normal';
});
Example Plunkr
This is how I do it in my app:
I have a main Controller that wraps everything.
<html ng-controller="AppCtrl">
<---- code --->
<body onload="onLoad()" class="{{ viewClass }}">
<div id="page" class="scale-fade-fast" ng-view></div>
<---- code --->
Route config of main module:
MainApp.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/path', {
viewClass: 'myPageClass',
templateUrl: 'path/to/tpl',
controller: 'AnotherCtrl'
})
<---- code --->
Listen on route change on main ctrl:
MainApp.controller('AppCtrl',['$scope', function($scope){
$scope.viewClass = 'defaultPageClass';
$scope.$on('$routeChangeSuccess', function(evt, current, previous){
if(current.viewClass) $scope.viewClass = current.viewClass;
});
}]);
I have an angular application similar to this:
<html>
<body ng-app="my-app" ngcloak ng-controller="MainCtrl">
...stuff...
<!-- Add your site or application content here -->
<div ng-view=""></div>
....
And the view is set by Routes:
.when('/maps', {
templateUrl: 'views/maps.html',
controller: 'MapsCtrl'
})
It works fine. What I'd like to know is how I can get a class from the current location, using the above example, assign a class "maps" to the body tag for page-specific CSS.
I would setup a listener in MainController like this:
$scope.$on('$routeChangeSuccess', function(newVal, oldVal) {
if (oldVal !== newVal) {
$scope.routeClassName = $route.current.className;
}
});
And in template:
<body ng-controller="mainController" ng-class="routeClassName">
Then you can configure routes like this:
$routeProvider
.when('/maps', {
controller: 'mapsController',
template: 'maps',
className: 'maps' // <--- class name
})
.when('/about', {
controller: 'aboutController',
template: 'about',
className: 'about' // <--- class name
})
Demo: http://plnkr.co/edit/QUaw6SkgPfR4IPyKniXG?p=preview
You could use the $location service to figure out the current location and then use ng-class to assign it to your body tag. e.g.
JS
var MainCtrl = function($scope, $location) {
$scope.$location = $location;
}
HTML
<body ng-class="{maps: '/maps' === '$location.path()'}"></body>
This is my template:
<div class="span12">
<ng:view></ng:view>
</div>
and this is my view template:
<h1>{{stuff.title}}</h1>
{{stuff.content}}
I am getting the content as html and I want to display that in a view, but all I am getting is raw html code. How can I render that HTML?
Use-
<span ng-bind-html="myContent"></span>
You need to tell angular to not escape it.
To do this, I use a custom filter.
In my app:
myApp.filter('rawHtml', ['$sce', function($sce){
return function(val) {
return $sce.trustAsHtml(val);
};
}]);
Then, in the view:
<h1>{{ stuff.title}}</h1>
<div ng-bind-html="stuff.content | rawHtml"></div>
In angular 4+ we can use innerHTML property instead of ng-bind-html.
In my case, it's working and I am using angular 5.
<div class="chart-body" [innerHTML]="htmlContent"></div>
In.ts file
let htmlContent = 'This is the `<b>Bold</b>` text.';
You shoud follow the Angular docs and use $sce - $sce is a service that provides Strict Contextual Escaping services to AngularJS. Here is a docs: http://docs-angularjs-org-dev.appspot.com/api/ng.directive:ngBindHtmlUnsafe
Let's take an example with asynchroniously loading Eventbrite login button
In your controller:
someAppControllers.controller('SomeCtrl', ['$scope', '$sce', 'eventbriteLogin',
function($scope, $sce, eventbriteLogin) {
eventbriteLogin.fetchButton(function(data){
$scope.buttonLogin = $sce.trustAsHtml(data);
});
}]);
In your view just add:
<span ng-bind-html="buttonLogin"></span>
In your services:
someAppServices.factory('eventbriteLogin', function($resource){
return {
fetchButton: function(callback){
Eventbrite.prototype.widget.login({'app_key': 'YOUR_API_KEY'}, function(widget_html){
callback(widget_html);
})
}
}
});
So maybe you want to have this in your index.html to load the library, script, and initialize the app with a view:
<html>
<body ng-app="yourApp">
<div class="span12">
<div ng-view=""></div>
</div>
<script src="http://code.angularjs.org/1.2.0-rc.2/angular.js"></script>
<script src="script.js"></script>
</body>
</html>
Then yourView.html could just be:
<div>
<h1>{{ stuff.h1 }}</h1>
<p>{{ stuff.content }}</p>
</div>
scripts.js could have your controller with data $scope'd to it.
angular.module('yourApp')
.controller('YourCtrl', function ($scope) {
$scope.stuff = {
'h1':'Title',
'content':"A paragraph..."
};
});
Lastly, you'll have to config routes and assign the controller to view for it's $scope (i.e. your data object)
angular.module('yourApp', [])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/yourView.html',
controller: 'YourCtrl'
});
});
I haven't tested this, sorry if there's a bug but I think this is the Angularish way to get data