Update $state variable in 1 module from another - javascript

https://plnkr.co/edit/PWuKuVw9Dn9UJy6l8hZv?p=preview
I have 3 modules, routerApp, tickers and tags. Basically trying to rebuild my app out of smaller mini-apps.
The routerApp template contains the 2 directives for the other modules.
Expected
When you login, then click on the Count button in the tickers.component, I want to send the counter var into the tags.component $scope via $state.go.
Result
Nothing happens. No $state/variable update in the tags.component
Plnkr app.js code:
// TICKERS app module
var tickers = angular.module('tickers', ['ui.router'])
tickers.config(function($stateProvider) {
const tickers = {
name: 'tickers',
url: '/tickers',
parent: 'dashboard',
templateUrl: 'tickers-list.html',
bindToController: true,
controllerAs: 'tik',
controller: function() {
}
}
$stateProvider
.state(tickers);
})
tickers.component('tickersModule', {
templateUrl: 'tickers-list.html',
controller: function($scope, $state) {
console.log('Tickers init')
$scope.counter = 0;
$scope.increase = function() {
$scope.counter++;
console.log('increase', $scope.counter)
$state.go('dashboard.tags', { counter: $scope.counter });
}
}
})
// TAGS app module
var tags = angular.module('tags', ['ui.router'])
tags.config(function($stateProvider) {
const tags = {
name: 'tags',
url: '/tags?counter',
parent: 'dashboard',
params: {
counter: 0
},
templateUrl: 'tags-list.html',
bindToController: true,
controllerAs: 'tags',
controller: function($state) {
}
}
$stateProvider
.state(tags);
})
tags.component('tagsModule', {
templateUrl: 'tags-list.html',
controller: function($scope, $state) {
// Expecting this to update:
console.log('Tags init', $state)
$scope.counter = $state.params.counter;
}
})
// MAIN ROUTERAPP module
var routerApp = angular.module('routerApp', ['ui.router', 'tickers', 'tags']);
routerApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/login');
const login = {
name: 'login',
url: '/login',
templateUrl: 'login.html',
bindToController: true,
controllerAs: 'l',
controller: function($state) {
this.login = function() {
$state.go('dashboard', {})
}
}
}
const dashboard = {
name: 'dashboard',
url: '/dashboard',
templateUrl: 'dashboard.html',
controller: function() {
}
}
$stateProvider
.state(login)
.state(dashboard);
})
dashboard.html
<div class="jumbotron text-center">
<h1>The Dashboard</h1>
</div>
<div class="row">
<tickers-module></tickers-module>
<tags-module></tags-module>
</div>
The function in the tickers component that is trying to update the $state of the tags component:
$scope.increase = function() {
$scope.counter++;
console.log('increase', $scope.counter)
$state.go('dashboard.tags', { counter: $scope.counter });
}
Also tried: $state.go('tags', { counter: $scope.counter });
Finally the tags.component.
Note that here I'm not seeing the $scope.counter update nor the controller for the component getting refreshed due to a state change.
tags.component('tagsModule', {
templateUrl: 'tags-list.html',
controller: function($scope, $state) {
console.log('Tags init', $state)
$scope.counter = $state.params.counter;
}
})
Is the way I am architecting this going to work? What am I missing?
Update: Added some $rootScope events to watch for $state changes, hope this helps:
This is after clicking the login button and going from the login state to the dashboard state, but still nothing for clicking on the Count button.

So, it looks like you're properly passing the parameters in your $state.go call.
I think the issue here is that you're not properly handling the state parameters you're passing from the tickers component to the tags component.
Try injecting $stateParams into your tags component and pull the parameters off that object, for example (in your tags controller):
$scope.counter = $stateParams.counter;

Figured it out!
https://plnkr.co/edit/CvJLXKYh8Yf5npNa2mUh?p=preview
My problem was that in the $state object tags, I was using the same template as the tags.component.
Instead I needed to change it to something like <p>{{ counter }}</p>
var tags = angular.module('tags', ['ui.router'])
tags.config(function($stateProvider) {
const tags = {
name: 'tags',
url: '/tags',
parent: 'dashboard',
params: {
counter: 0
},
template: '<p>{{ counter }}</p>',
bindToController: true,
controller: function($scope, $state) {
console.log('tags state object', $state)
$scope.counter = $state.params.counter;
}
}
$stateProvider
.state(tags);
})
tags.component('tagsModule', {
templateUrl: 'tags-module-template.html',
controller: function($scope, $state) {
}
})
Then in my tags-module.template.html I needed to add a <div ui-view></div>
<div class="jumbotron text-center">
<h2>Tags list</h2>
<div ui-view></div> // <- here and this is where the $state object updates
{{ counter }}
</div>

Related

In Angular ui-router, for nested state, corresponding template is not rendering?

I want to show tab(profile+setting), like the following image, but when i click on any tabs, corresponding template is not loading. In customerinfo.view.html I tried to change <div ui-view="{{tab.view}}"></div> to <div ui-view></div> it causing me infinite digest cycle.
I am able to change the url, When first time we hit the url http://localhost:3000/home/#/updatecustomer/3/ following time opens, when click on profile, url change to http://localhost:3000/home/#/updatecustomer/3/profile, but corresponding template(profile.html) is not loading, same is happening for setting
I go through this stackoverflow question, but no help
Module definition
(function() {
'use strict';
var app = angular.module('app', ['ui.router', 'ngCookies', 'ui.bootstrap']);
app.config(function config($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider
.state('home', {
url: '/',
controller: 'HomeController',
templateUrl: 'home/home.view.html',
})
.state('home.updatecustomer', {
url: 'updatecustomer/:customerId/',
controller: 'TabsDemoCtrl',
templateUrl: 'addcustomer/customerinfo.view.html',
})
.state('home.updatecustomer.profile', {
url: 'profile',
controller: 'ProfileCtrl',
templateUrl: 'addcustomer/profile.html',
}))
.state('home.updatecustomer.setting', {
url: 'setting',
controller: 'SettingCtrl',
templateUrl: 'addcustomer/setting.html',
})
customer.js
(function () {
'use strict';
var app = angular.module('app');
app.controller('TabsDemoCtrl', TabsDemoCtrl);
TabsDemoCtrl.$inject = ['$scope', '$state'];
function TabsDemoCtrl($scope, $state){
$scope.customer = 3;
$scope.tabs = [
{ title:'profile', view:'profile', active:true },
{ title:'setting', view:'setting', active:false }
];
}
})();
customerinfo.view.html
<uib-tabset active="active">
<uib-tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" disable="tab.disabled">
<div ui-view="{{tab.view}}"></div>
</uib-tab>
</uib-tabset>
profile.js
(function () {
'use strict';
var app = angular.module('app') ;
app.controller('ProfileCtrl', ProfileCtrl);
ProfileCtrl.$inject = ['$scope'];
function ProfileCtrl($scope){
$scope.profile="Profile 123";
}
})() ;
profile.html
profile
Setting.js
(function () {
'use strict';
var app = angular.module('app') ;
app.controller('SettingCtrl', SettingCtrl);
SettingCtrl.$inject = ['$scope'];
function SettingCtrl($scope){
$scope.setting="setting 1213";
}
})() ;
setting.html
setting
Edit:
1) The first thing-- the naming of your urls. Instead of http://localhost:3000/home/#/updatecustomer/3/ the url should be http://localhost:3000/#/updatecustomer/3/
2) You want the tabs to be children of your home state. Do this by setting abstract: true.
$stateProvider
.state('home', {
abstract: true,
controller: 'HomeController',
templateUrl: 'home/home.view.html'
})
3) The url for your routes must begin with a /.
.state('home.your-splash-view', {
url: '/home',
controller: 'HomeCtrl',
templateUrl: 'home/splash.view.html'
})
.state('home.updatecustomer', {
url: '/updatecustomer/:customerId/',
controller: 'TabsDemoCtrl',
templateUrl: 'addcustomer/customerinfo.view.html'
})
.state('home.updatecustomer.profile', {
url: '/profile',
controller: 'ProfileCtrl',
templateUrl: 'addcustomer/profile.html'
});
4) Consider navigating states with theui-sref directive.
Something like:
<uib-tab ui-sref='home.updatecustomer.profile'> ... </ui-tab>
Related:
what is the purpose of use abstract state?
Why give an "abstract: true" state a url?

Implementing a navbar nested view in angular ui router

Am new to the angular js.
Am implementing a nested ui view but the problem is when checking the current state of a page it returns many objects such that i cant use $state.current to set the ng-show
I would like the navbar shown and hidden in some states.
I have tried
The main index.html page
<html>......
<body ng-app="myapp">
<nav ng-controller="headerCtrl" ng-show="shownav()" >
//here is the navbar code..The shownav is defined on the headerCtrl
</nav>
<div ui-view> </div>
//Angular js, controllers and services links
</body>
</html>
The app.js code
var app = angular.module('myApp', ['ui.router']);
app.controller('headerCtrl',function($scope, $state) {
$scope.shownavbar = function(){
var state = $state.current;
if(state ==='login' ){
return false;
}else{
return true;
}
}
app.config(function($stateProvider, $urlRouterProvider, $httpProvider){
$stateProvider
.state('login', {
url:'/login',
templateUrl: 'templates/index/login/login.html',
controller: 'loginCtrl'
})
.state('dash', {
url: '/dash',
templateUrl:'templates/layout/dashboard.html',
abstract:true
})
.state('dash.call',{
url: '/call',
templateUrl: 'templates/index/calls/calls.html',
controller: 'callCtrl'
})
.state('dash.profile', {
url: '/profile',
templateUrl: 'templates/index/account/profile/profile.html',
controller: 'profileCtrl'
})
});
I would like the navbar hidden for some states like when a user is on the login state
At the headerctrl i have also tried
$scope.shownavbar = function(){
var state = $state.current;
$log.info(state);
}
This returns in the console:
angular.js:13708 Object {name: "", url: "^", views: null, abstract: true}
angular.js:13708 Object {name: "", url: "^", views: null, abstract: true}
angular.js:13708 Object {url: "/login", templateUrl: "templates/index/login/login.html", controller: "loginCtrl", name: "login"}
angular.js:13708 Object {url: "/login", templateUrl: "templates/index/login/login.html", controller: "loginCtrl", name: "login"}
angular.js:13708 Object {url: "/login", templateUrl: "templates/index/login/login.html", controller: "loginCtrl", name: "login"}
WHAT COULD BE THE PROBLEM
I can think in two ways to solve this.
First solution
EDITED
inside your run() put a function to see when the state is changing and hide or show the navbar.
myApp.run(function ($rootScope, $state) {
$rootScope.navbar = false;
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if (toState.name === 'login') {//toState variable see the state you're going
$rootScope.navbar = false;
} else {
$rootScope.navbar = true;
}
});
});
and change in your ng-show="navbar"
Second solution
the second solution i can think is you use multiple views.
$stateProvider
.state('login', {
url: '/',
views: {
'navbar': {
templateUrl: null,
controller: null
},
'body': {
templateUrl: "views/login.html",
controller: 'LoginController'
}
}
})
.state('home', {
url: '/home',
views: {
'navbar': {
templateUrl: "views/navbar.html",
controller: null
},
'body': {
templateUrl: "views/inicio.html",
controller: null
}
}
});
and in your html views put something similar to this:
<div ui-view="navbar"></div>
<div ui-view="body"></div>

dynamic nested view with angular component

i have an angularjs app with components and i want to add a view as child of another view using ui.router. i honestly dont think that ui.router fully support component, this may happen in upcomping 1.0 version. But in the meanwhile is anything that i can do to use display view dynamically?
this is my $stateProvider (i've done my attempts)
$stateProvider
.state('home', {
url :'/home',
template :'<home></home>'
})
.state('projects', {
url:'/projects',
template: "<project-list></project-list>"
})
.state('projectDetails',{
url:'/:projectId',
template : '<project-detail projectDetails="projectDetails"></project-detail>'
, views :{
'chat':{
template : '<chat></chat>'
}
}
});
$urlRouterProvider.otherwise('home');
i have created a component in this way:
(function() {
'use strict';
function ChatController($scope, $element, $attrs, $firebaseArray) {
var ctrl = this;
console.log("it works");
}
angular.module('myapp').component('chat', {
templateUrl: '/app/component/project/chat.html',
controller: ChatController
});
})(window.angular);
and then i've added the view in projectDetails
<div ui-view="chat"></div>
My understanding of your requirement is that you have a component called 'Chat' which you want to load in the state 'project-details' as a nested/child view.
As you have already observed ui-router does not support this.
But this can be achieved by making your 'project-details' as a parent state and load other components included as a child state.
Plunker Demo
angular.module('app', [
'ui.router'
]).config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider.state('home', {
template: '<home></home>'
}).state('home.parts', {
url: '/',
views: {
'about-view#home': {
template: "<about></about>"
},
'chat-view#home': {
template: "<chat></chat>"
}
}
});
}).component('app', {
templateUrl: 'app.html'
}).component('home', {
templateUrl: 'home.html',
controller: homeController,
controllerAs: 'vm'
}).component('about', {
templateUrl: 'about.html',
controller: aboutController,
controllerAs: 'vm'
}).component('chat', {
templateUrl: 'chat.html',
controller: chatController,
controllerAs: 'vm'
});
function chatController() {
this.name = "chat";
}
function aboutController() {
this.name = "about";
}
function homeController() {
this.name = "home";
}
Hope this is what you wanted.Please do not add url to the parent state.Consider making it a abstract state.

Want to update parent view values from Child View using UI-Router

I am new to AngularJS and I am using Angular UI-Router for my SPA.
What I am trying to do is to update the Parent View values from the Child View. I have gone through the UI-Router documentation for Nested Views and Multiple Views but couldn't find a way to update the values.
My use case is, Parent view will be the Header and every time a Child View changes via the State Transition I want to update the header value which is part of the Parent View.
Code :
HTML File -
<div ui-view></div>
JS File where Angular UI-Routing configuration happens -
angular.module('myApp', ['ui.router']).config(['$stateProvider', '$routeProvider',
function($stateProvider, $routeProvider) {
$stateProvider
.state('main', {
resolve: {
resA: function() {
return {
'value': 'Hello !!'
};
}
},
controller: function($scope, resA) {
$scope.resA = resA.value;
},
abstract: true,
url: '/main',
template: '<h1>{{resA}}</h1>' +
'<div ui-view></div>'
})
.state('main.one', {
url: '/one',
views: {
'#main': {
template: "Im View One"
}
},
resolve: {
resB: function(resA) {
return {
'value': resA.value + ' from One'
};
}
},
controller: function($scope, resA, resB) {
$scope.resA = resB.value;
}
}).state('main.two', {
url: '/two',
views: {
'#main': {
template: '<div ui-view="sub1"></div>' +
'<div ui-view="sub2"></div>'
},
'sub1#main.two': {
template: "Am awesome"
},
'sub2#main.two': {
template: "Am awesome two/too"
}
},
resolve: {
resC: function(resA) {
return {
'value': resA.value + ' from Two'
};
}
},
controller: function($scope, resA, resC) {
$scope.resA = resC.value;
}
});
}]).run(['$rootScope', '$state', '$stateParams', function($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$state.transitionTo('main.two');
}]);
Here is the JSFiddle Link of the same code snippet.
There are muliple ways you can update the parent scope.
Using controllerAs
https://jsfiddle.net/9n7wrevt/17/
controller: function($scope, resA) {
this.resA = resA.value;
},
controllerAs: 'main'
referring parent as below
controller: function($scope, resB) {
$scope.main.resA = resB.value;
}
Using $parent
https://jsfiddle.net/9n7wrevt/18/
controller: function($scope, resB) {
$scope.$parent.resA = resB.value;
}
Better way(highly recommended) is to use $scope $emit, $on to communicate between controllers.
https://jsfiddle.net/9n7wrevt/19/

How can I have multiple instances of one controller for multiple templates

Trying to use a reusable controller for a generic template
html
<div class="row col-lg-10 pull-right">
<div ng-init="catId = 1" ui-view="firstQuadrant"></div>
<div ng-init="catId = 2" ui-view="secondQuadrant"></div>
</div>
<div class="row col-lg-10 pull-right">
<div ng-init="catId = 3" ui-view="thirdQuadrant"></div>
<div ng-init="catId = 4" ui-view="fourthQuadrant"></div>
</div>
code snippet from my views object in $stateProvider:
views : {
'firstQuadrant#home': {
templateUrl: "../partials/quadrant/quadrant.html",
controller: "QuadrantCtrl"
},
'secondQuadrant#home': {
templateUrl: "../partials/quadrant/quadrant.html",
controller: "QuadrantCtrl"
},
'thirdQuadrant#home': {
templateUrl: "../partials/quadrant/quadrant.html",
controller: "QuadrantCtrl"
},
'fourthQuadrant#home': {
templateUrl: "../partials/quadrant/quadrant.html",
controller: "QuadrantCtrl"
}
}
controller code
.controller('QuadrantCtrl', ['$scope', '$rootScope', 'categories', 'utils',
function ($scope, $rootScope, categories, utils) {
$scope.$watch('catId', function () {
console($scope.catId);
$scope.categories = categories;
$scope.name = "It works! weee";
$scope.score = 99;
$scope.items = utils.findById($scope.categories, $scope.catId);
});
}]);
It only seems to use the last controller being instantiated (catId = 4)
how can I have 4 isolated scopes? Do I have to use directives instead?
Your scenario should work (not sure if this is good design). There is a working plunker
But we have to move the switch catId from ng-init into state defintion. Into resolve
If the states are defined like this:
// home
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'tpl.layout.html',
controller : "rootController",
})
the child state with multi-views
.state('child', {
parent: "home",
url: '/child',
templateUrl: 'tpl.example.html',
views : {
'firstQuadrant#home': {
templateUrl: "tpl.quadrant.html",
controller: "QuadrantCtrl",
resolve: { catId : function(){ return 1 } },
},
'secondQuadrant#home': {
templateUrl: "tpl.quadrant.html",
controller: "QuadrantCtrl",
resolve: { catId : function(){ return 2 } },
},
'thirdQuadrant#home': {
templateUrl: "tpl.quadrant.html",
controller: "QuadrantCtrl",
resolve: { catId : function(){ return 3 } },
},
'fourthQuadrant#home': {
templateUrl: "tpl.quadrant.html",
controller: "QuadrantCtrl",
resolve: { catId : function(){ return 4 } },
}
}
})
And simplified controller creates random number in the scope
.controller('QuadrantCtrl', ['$scope', '$rootScope', 'catId'
, function ($scope, $rootScope, catId) {
$scope.catId = catId;
console.log($scope.catId);
$scope.random = Math.random() * 100;
}])
Each view is then independent with its own instance of controller and $scope
Check it here
Then we can see results like this
quadrant
random number in the scope: 32.40865177940577
catId: 1
quadrant
random number in the scope: 17.18798188958317
catId: 2
quadrant
random number in the scope: 76.22438217513263
catId: 3
quadrant
random number in the scope: 41.46456739399582
catId: 4
if the quadrant template is:
<h4>quadrant</h4>
<p>random number in the scope: {{random}}</p>
<p>catId: {{catId}}</p>
All that is strictly following the documentation:
Multiple Named Views
The working example with above stuff

Categories

Resources