How to watch Route changes in AngularJS component (v1.5.8) - angularjs

I'm building the app in AngularJS 1.5.8.
I've a main root component called app.component.
in app.component, I wanna watch all routes changes which happens navigating between child components.
And in watch, I need to get routeParams, as well.
I've defined the routes via $routeConfig in angularjs component-router
I've tried with this.$routerOnActivate but it wasn't called because I'm on root component.
var controller = function ($scope) {
$scope.$on('$routeChangeSuccess', (event, data) => {
// This is called everytime route is changed
// Here, I need to get the routeParams
// Not sure this is the correct way to watch route changes in angular component-router
});
}
angular
.module('example')
.component('RootComponent', {
templateUrl: 'app/components/enter/enter.component.html',
controller: controller,
$routeConfig: [
{path: '/a', name: 'AComponent', component: 'AComponent', useAsDefault: true},
{path: '/b', name: 'BComponent', component: 'BComponent'},
]
});
Thanks.
PS
I've tried with How to watch for a route change in AngularJS?.
It was called everytime I change the route but I can't get routerParams from it.
On the official doc, it said 3 params are available - $event, current, next but only $event is coming, the rest is undefined.
I thinks it's working when we define routes via $routeProvider but not in my case.

Related

Is possible to add controller on ui-router lazyload function

I'm trying to lazyload my controller with pure ui-router lazyload function as :
I've tried the two follow exemples
1.
$stateProvider.state('profile', {
url: '^/profile',
template: view,
controller:'profileController',
security: true
, lazyLoad: function ($transition, $state) {
angular.module('profileModule').controller('profileController', require('./components/profile/controller.js') ;
}
});
In this exemple when load the state the error of controller no registred appear, even tho the docs of ui-router says lazyload functions is called before the state change.
2.
$stateProvider.state('profile', {
url: '^/profile',
template: view,
security: true
, lazyLoad: function ($transition, $state) {
angular.module('profileModule').controller('profileController',require('./components/profile/controller.js');
$state.controller = 'profileController';
}
});
In this no error is shown on console, but the controller is not attached to the state.
Any regards on that?
and no i cant use oclazyload for reasons i cant explain :/
Please haaaaaalp

ui-router is reloading controller

Using ui-router 1.0.6.
Every time I return to an url (using ui-sref) it reloads the controller. I would like to avoid that and to load the controller only the first time it is accessed.
In this example Plunkr: every time I switch repeatedly between Hello and About it logs the console.
It can be wrapped in a parent controller to track who's already loaded
Here is a working example: Plnkr
Basically you create another controller that holds an object with an empty list:
myApp.controller('ModuleNumCtrl', function() {
loadedCtrl = {};
});
And set it to be parent by setting the abstract attribute to true:
var parentState = {
abstract: true,
name: 'parent',
controller: 'ModuleNumCtrl'
};
Then you set the the exiting controllers to be his children by prefixing their names with 'parent.'
var helloState = {
name: 'parent.hello',
url: '/hello',
template: '<h3>hello world!</h3>',
controller: 'ModuleTwoCtrl'
};
var aboutState = {
name: 'parent.about',
url: '/about',
template: '<h3>Its the UI-Router hello world app!</h3>',
controller: 'ModuleOneCtrl'
};
$stateProvider.state(parentState);
$stateProvider.state(helloState);
$stateProvider.state(aboutState);
Then on each controller you want to load only once, you can add it to the list the first time it's loaded and the code that you want to run only once put in an if statement:
myApp.controller('ModuleOneCtrl', function() {
if (!loadedCtrl.one) {
console.log("One");
}
loadedCtrl.one = true;
});
Last thing, don't forget to change the HTML with the new controllers names:
<a ui-sref="parent.hello" ui-sref-active="active">Hello</a>
<a ui-sref="parent.about" ui-sref-active="active">About</a>
There's a plugin for ui-router which can do that, named sticky-states: https://github.com/ui-router/sticky-states
I would build on top of your plunker, but i can't find a CDN that's hosting sticky states. I found a CDN for ui-router-extras which is the equivalent for sticky states in ui-router 0.x, but for 1.x that won't work.
What you'll need to do is
1) Add the plugin. The github page for sticky-states gives instructions on how to do this, which i'll replicate here:
import {StickyStatesPlugin} from "ui-router-sticky-states";
angular.module('myapp', ['ui.router']).config(function($uiRouterProvider) {
$uiRouterProvider.plugin(StickyStatesPlugin);
});
2) For the state definitions that you want to remain active, add the property sticky: true, as in:
var aboutState = {
name: 'about',
url: '/about',
template: '<h3>Its the UI-Router hello world app!</h3>',
controller : 'ModuleOneCtrl',
sticky: true
}
With this flag, moving from a state to a sibling state will not exit the old state, but rather will "inactivate" it. The controller remains loaded. If you try to enter that old state, it will be "reactivated". The state is now active, but the existing controller is reused.
Note that sticky states will still be exited if you do one of the following:
1) exit the parent of the sticky state
2) directly activate the parent of the sticky state
So you'll need to arrange your tree of states so that that either can't happen , or only happens when you want it to.

Passing object to all components from parent state in UI-Router

I revisited AngularJS after a long. Pleased to see they've gone ahead with components. I am trying to make use of components in my project.
I have few child component states that require access to parent component state. Basically an object will be shared across all child states. I am unable to achieve that with components.
Here's how the structure looks like -
{
name: 'wizard',
url: '/wizard',
component: 'wizard',
redirectTo: 'wizard.init'
},
{
name: 'wizard.init',
url: '/init',
component: 'init'
},
{
name: 'wizard.customize',
url: '/customize',
component: 'customize'
},
{
name: 'wizard.finish',
url: '/finish',
component: 'finish'
}
There is an object / variable called $ctrl.settings in wizard component which I want to be shared across all it's child states.
I tried doing something like this -
<div ui-view settings="settings">
And accessing them in child components like this -
(function(angular){
var app = angular.module('app');
app.component('init', {
templateUrl:'Scripts/dist/views/modules/wizard/init.html',
controller: WizInit,
bindings : {
'settings' : '='
}
});
function WizInit(){
var $ctrl = this;
$ctrl.$onInit = function(){
console.log("init Start Step");
console.log($ctrl.WizInit);
$ctrl.WizInit= "start";
}
}
})(window.angular);
But I get undefined in every state even though I have assigned it to some value in parent component /wizard.
How can I make it work with components and ui-router?
Never mind,
Solved it on my own. I just had to add $ctrl in ui-view directive of parent component state..
<div ui-view settings="$ctrl.settings">
Drawback of working late. You are not productive enough sometimes.

angular ui router: component $onInit fires twice on route change

I am using angular-ui-router 0.2.18 with angular 1.5.x. I cannot explain why my component $onInit fires twice (I do not think it is relevant to my problem, but I am also using webpack).
My routing:
myModule.config(function ($stateProvider) {
$stateProvider
.state('app.project', {
abstract: true,
url: '/project',
template: '<ui-view/>'
})
.state('app.project.demo', {
url: '/demo',
template: '<my-component></my-component>'
});
});
A barebone version of my component:
myModule.component('myComponent', {
template: require('./my-component.html'),
bindings: {},
controller: function () {
this.alert = function () {
console.log("fires");
};
this.$onInit = function () {
this.alert();
};
}
});
Somewhere in my application, the route change is triggered by <a ui-sref="app.project.demo"></a>.
The alert function fires twice when I click the link, but not when I reload the page. Maybe the controller is loaded twice on route change ?
I have tried everything listed on this SO question: combating-angularjs-executing-controller-twice, but without success.
What really puzzles me though, is that the issue disappears when I rename my state name without changing anything else:
'app.project.demos' works
'app.projects.demo' works too (after changing 'app.project' to 'app.projects'of course)
What could be the explanation ?

Where should I place code to be used across components/controllers for an AngularJS app?

Should it be associated with the app module? Should it be a component or just a controller? Basically what I am trying to achieve is a common layout across all pages within which I can place or remove other components.
Here is what my app's structure roughly looks like:
-/bower_components
-/core
-/login
--login.component.js
--login.module.js
--login.template.html
-/register
--register.component.js
--register.module.js
--register.template.html
-app.css
-app.module.js
-index.html
This might be a bit subjective to answer but what I personally do in a components based Angular application is to create a component that will encapsulate all the other components.
I find it particularly useful to share login information without needing to call a service in every single component. (and without needing to store user data inside the rootScope, browser storage or cookies.
For example you make a component parent like so:
var master = {
bindings: {},
controller: masterController,
templateUrl: 'components/master/master.template.html'
};
function masterController(loginService) {
var vm = this;
this.loggedUser = {};
loginService.getUser().then(function(data) {
vm.loggedUser = data;
});
this.getUser = function() {
return this.loggedUser;
};
}
angular
.module('app')
.component('master', master)
.controller('masterController', masterController);
The master component will take care of the routing.
index.html:
<master></master>
master.template.html:
<your common header>
<data ui-view></data>
<your common footer>
This way, every component injected inside <ui-view> will be able to 'inherit' the master component like so:
var login = {
bindings: {},
require: {
master: '^^master'
},
controller: loginController,
templateUrl: 'components/login/login.template.html'
};
and in the component controller
var vm=this;
this.user = {};
this.$onInit = function() {
vm.user = vm.master.getUser();
};
You need to use the life cycle hook $onInit to make sure all the controllers and bindings have registered.
A last trick to navigate between components is to have a route like so (assuming you use ui-router stable version):
.state('home',
{
url : '/home',
template : '<home></home>'
})
which will effectively route and load your component inside <ui-view>
New versions of ui-router include component routing.

Resources