Re-use URI in many angular UI-Router state - angularjs

I tried to re-use a url for several states with angular UI-Router.
I tried to do that :
.state('app.contracts', {
url: '/contracts',
controller: function($rootScope, $scope, $state) {
if ($rootScope.isDistributor) {
$state.go('app.contracts-distributor');
} else if ($rootScope.isShop) {
$state.go('app.contracts-shop');
} else if ($rootScope.isVendor) {
$state.go('app.contracts-vendor');
}
}
})
.state('app.contracts-distributor', {
controller: 'ContractDistributorController',
templateUrl: 'views/contracts/list-distributor.html'
})
.state('app.contracts-shop', {
controller: 'ContractShopController',
templateUrl: 'views/contracts/list-shop.html'
})
.state('app.contracts-vendor', {
controller: 'ContractVendorController',
templateUrl: 'views/contracts/list-vendor.html'
})
But when I try this I have an infinite loop.
Any idea what I'm doing wrong?

There is a working plunker
Not sure about the concept, what is the real goal ... but it should work. This is the adjusted state (just to go somewhere on ELSE):
.state('app', { template: '<div ui-view=""></div>', })
.state('app.contracts', {
url: '/contracts',
controller: ['$rootScope', '$scope', '$state',
function($rootScope, $scope, $state) {
if ($rootScope.isDistributor) {
$state.go('app.contracts-distributor');
} else if ($rootScope.isShop) {
$state.go('app.contracts-shop');
} else { // if ($rootScope.isVendor) {
$state.go('app.contracts-vendor');
}
}]
})
I used array controller notation and ng-strict-di, just to avoid later issues with minification. And assured, that parent state app has target ui-view=""
Check it here

Related

UI Resolve is not injecting into controller (data is undefined)

I've looked at similar questions but I can't seem to understand what I am missing. Basically, I have a service that gets data from the server, and I am trying to get that data into a controller through UI-Router's resolve property. However, after following numerous tutorials and documentations, I can't get the controller to find the data, so to speak. Everything comes up as undefined. I am hoping someone can help me understand what is happening. My code is below.
services.js
myServices.factory('SoundCloudService', ['$http', '$log', '$sce', function($http, $log, $sce) {
function getPlayerHtml() {
return $http.get('/get-site-data').then(function(oEmbed) {
return $sce.trustAsHtml(oEmbed.data.player);
});
};
function getSiteAbout() {
return $http.get('/get-site-data').then(function(oEmbed) {
return $sce.trustAsHtml(oEmbed.data.about);
});
}
function getAllTracks() {
return $http.get('/get-all-tracks').then(function(tracks) {
return JSON.parse(tracks.data);
});
};
function getAllPlaylists() {
return $http.get('/get-playlists').then(function(playlists) {
return JSON.parse(playlists.data);
})
};
function getPlaylist(pid) {
return $http.post('/get-playlist', pid, $http.defaults.headers.post).then(function(playlist) {
return playlist.data;
});
};
function getXMostTrendingFrom(x, playlist) {
var i, trending = [];
playlist.sort(function(a, b) { return b.playback_count - a.playback_count} );
for(i=0;i<x;i++) {
trending.push(all_tracks[i]);
}
return trending;
};
return {
getAllTracks: getAllTracks,
getAllPlaylists: getAllPlaylists,
getPlayerHtml: getPlayerHtml,
getSiteAbout: getSiteAbout,
getXMostTrendingFrom: getXMostTrendingFrom,
getPlaylist: getPlaylist,
};
}]);
app.js
myApp.config(['$stateProvider', '$urlRouterProvider', 'ngMetaProvider',
function($stateProvider, $urlRouterProvider, ngMetaProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('main', {
url: '',
template: '<ui-view/>',
abstract:true,
controller: 'MainController',
resolve: {
player: function(SoundCloudService) { return SoundCloudService.getPlayerHtml(); },
about: function(SoundCloudService) { return SoundCloudService.getSiteAbout(); },
}
})
.state('main.home', {
url: '/',
templateUrl: '../static/partials/home.html',
controller: 'IndexController',
})
.state('main.team', {
url: '/team',
templateUrl: '../static/partials/team.html',
controller: 'TeamController',
})
.state('main.contact', {
url: '/contact',
templateUrl: '../static/partials/contact.html',
controller: 'ContactController',
})
.state('main.resources', {
url: '/resources',
templateUrl: '../static/partials/resources.html',
controller: 'ResourcesController',
})
.state('main.listen-to', {
url: '/listen-to',
templateUrl: '../static/partials/listen-to.html',
controller: 'ListenController',
})
.state('main.listen-to.season', {
url: '/listen-to/:season',
templateUrl: '../static/partials/listen-to.season.html',
controller: 'ListenController',
})
.state('main.listen-to.season.episode', {
url: '/listen-to/:season/:episode',
templateUrl: '../static/partials/listen-to.season.episode.html',
controller: 'ListenController',
})
.state('main.read', {
url: '/read',
templateUrl: '../static/partials/read.html',
controller: 'ReadController',
})
.state('main.read.post', {
url: '/read/:post',
templateUrl: '../static/partials/read.post.html',
controller: 'ReadController',
})
}
]);
controller.js
myControllers.controller('MainController', ['$scope', '$log', 'PageTitleService',
function($scope, $log, PageTitleService, player) {
$log.log(player); /* This is always undefined */
}
]);
[UPDATE]
As pointed out by Hadi in the answer below, I placed player in the array, and the controller now looks like this:
skodenControllers.controller('MainController', ['$scope', '$log', '$sce', 'PageTitleService', 'player',
function($scope, $log, $sce, PageTitleService, player) {
$log.log(player);
}
]);
The console DOES show the data, but only after an error as such:
Error: [$injector:unpr]
http://errors.angularjs.org/1.3.2/$injector/unpr?p0=playerProvider%20%3C-%20player
at angular.js:38
at angular.js:3930
at Object.d [as get] (angular.js:4077)
at angular.js:3935
at d (angular.js:4077)
at Object.e [as invoke] (angular.js:4109)
at F.instance (angular.js:8356)
at angular.js:7608
at r (angular.js:347)
at I (angular.js:7607)
Hopefully someone can lead me in the right direction.
You forgot pass player into array. change to this
myControllers.controller('MainController', ['$scope', '$log',
'PageTitleService','player',
function($scope, $log, PageTitleService, player) {
$log.log(player); /* This is always undefined */
}
]);
As myServices and myControllers are both modules, ensure you add them as dependencies of myApp module.
// init myApp module
angular.module('myApp', ['myServices', 'myControllers']);
Edit
Some leads :
According to the documentation, when using ui-router nested views, child views (state name = main.xxx) must declare the parent state, so you must add parent: "main" or child views won't inherit resolved properties of main state controller
As siteDate is loaded asynchronously in SoundCloudService (services.js:23), you cannot be sure it will be available in your controllers which are loaded at the same time.
Instead, add a getSiteDate() method to SoundCloudService which returns a promise. siteData is then cached and immediately return by the promise.
For example :
/**
* #name getSiteData
* #description Scrap site data
* #returns {promise} a promise
*/
function getSiteData() {
var deferred = $q.defer();
if(siteData) {
deferred.resolve(siteData);
}
else {
$http.get('/get-site-data').then(function(response) {
siteData = response.data;
deferred.resolve(siteData);
}, function(err) {
deferred.reject(err.message);
});
}
return deferred.promise;
}
Why trying to map SoundCloudService to siteData ? You should simply inject SoundCloudService in controllers that use it :
For example :
skodenControllers.controller('MainController', ['$scope', '$log', '$sce', 'PageTitleService', 'SoundCloudService',
function($scope, $log, $sce, PageTitleService, SoundCloudService) {
// Note: getSiteData() could use a cache inside the service
SoundCloudService.getSiteData().then(function(siteData) {
...
});
}

ionic angularjs give variable trough tabcontroller

I am totally new with angularjs and the ionic framework, but for a school project I need to make a app so I thought this was the best was.
But right now I face a problem, I am using the ionic tabcontroller and I want to give a variable with the tabs.
Here is a screenshot to explain how it need to works.
I hope someone can help me.
Edit:
routes.js:
.state('tabsController.dos', {
url: '/dos/:itemid',
views: {
'tab1': {
templateUrl: 'templates/dos.html',
controller: 'dosCtrl',
controller: function ($stateParams, $location, $http, $scope, $sce) {
$scope.reload = function() {
$state.reload();
};
console.log($stateParams.itemid);
$http.get('https://host/app/php/info.php?landid='+$stateParams.itemid+'&actie=dos')
.success(function(response){
$scope.dynamicHtml = $sce.trustAsHtml(response);
});
}
}
}
})
.state('tabsController.dont', {
url: '/donts/:itemid',
views: {
'tab2': {
templateUrl: 'templates/dont.html',
controller: 'dontCtrl'
}
}
})

$scope not reflecting data in view, while $rootscope is reflecting?

I am stuck with this from around one week. I am resolving my todo_id on "TodoDetailController", and then using a service to get todo details. But the controller is not working as expected. When I write a simple data on $scope its just not reflecting in my view, but the data in $rootscope is reflecting, But I don't want to use $rootscope everywhere.
Can someone please solve my query?
Here is the github project https://github.com/udayghulaxe/ticitic_todo
This is the project structure
This is what I have done so far
/************* My states config ************************/
.state('dashboard', {
url: '/dashboard',
abstract: true,
views: {
'': { templateUrl: './partials/main.html'},
'header_toolbar#dashboard': { templateUrl: './views/header_toolbar.html' },
'sidenavleft#dashboard': { templateUrl: './views/sidenav.html' },
'widgets#dashboard': { templateUrl: './views/widgets.html'},
'todo_detail#dashboard': { templateUrl: './views/todo_detail.html' }
}
})
.state('dashboard.listdetail', {
url: '/lists/:list_id/',
templateUrl: './partials/list.detail.html',
controller:'ListController',
resolve: {
list_id: function($stateParams){
return $stateParams.list_id;
}
},
data: {
authorizedRoles: [USER_ROLES.user],
pageTitle: 'Lists'
}
})
.state('dashboard.tododetail', {
url: '/lists/:list_id/:todo_id',
templateUrl: './partials/list.detail.html',
controller:'TodoDetailController',
resolve: {
list_id: function($stateParams){
//console.log($stateParams);
return $stateParams.list_id;
},
todo_id: function($stateParams){
//console.log($stateParams);
return $stateParams.todo_id;
}
}
})
/**************** My conrtoller *******************/
app.controller("TodoDetailController",['$rootScope','$scope','$state', '$q', 'UserService', '$window','AuthService','DataService','AUTH_EVENTS','list_id','$mdSidenav','todo_id',
function($rootScope,$scope, $state, $q, UserService, $window, AuthService, DataService,AUTH_EVENTS,list_id,$mdSidenav,todo_id)
{
/********* This data is not relecting at all **********/
$scope.list_id = list_id.toString();
$scope.current_list = UserService.GetTodoBylistid($rootScope.lists, $scope.list_id);
$scope.value = 'Not refelcting in view';
/**************** This is updating in view ***************************/
$rootScope.value2 = 'refelcting in view';
$scope.$watch(todo_id, function() {
$rootScope.todo_id = todo_id;
}, true);
toggleSidenav('right');
};
}]);
Inject $rootscope after $scope like this
app.controller("TodoDetailController",['$scope','$state','$rootScope', '$q', 'UserService', '$window','AuthService','DataService','AUTH_EVENTS','list_id','$mdSidenav','todo_id',
function($scope, $state, $rootScope, $q, UserService, $window, AuthService, DataService,AUTH_EVENTS,list_id,$mdSidenav,todo_id)
]);

$stateChangeSuccess, always the same value of $state.params

I can't wrap my head around this, I'm really struggling with ui-routeand $stateChangeSuccess and $watch, got two issues. I'm trying to change a value of a parameter, when I change the state, click a url. I think it's important to know that I use sub-states. With my current setup I get that the $stateChangeSuccess triggers twice on load, meaning it sets the value right away. What I'm trying to do is to only have it set on change of url.
My route looks like this, I'm trying to set the value of a parameter
.state('medications', {
url: '/medications',
templateUrl: '/partials/home.html',
controller: 'mainController',
params: { showSection: false },
resolve: {
postPromise: ['medicationservice', function(medicationservice) {
return medicationservice.getAll();
}]
}
})
.state('medications.add', {
url: '/add',
templateUrl: '/partials/home.html',
controller: 'mainController',
params: { showSection: true },
})
in my controller I got the following, where I set the openSesame parameter to false explicitly on init, but as described it triggers and sets it to true.
mainModule.controller('mainController', [
'$scope',
'$state',
'$rootScope',
'medicationservice',
function($scope, $state, $rootScope, medicationservice) {
$scope.medication = {};
$scope.medications = medicationservice.posts;
$scope.openSesame = false;
$rootScope.$on("$stateChangeSuccess", function() {
$scope.openSesame = true;
console.log($scope.openSesame);
});
}]);
in my plunker the state change works once, that is if I use the $rootScope.
You can actually use $stateChangeSuccess without $injecting $rootScope. You can set a listener on the $scope object instead. Take a look at the following plunker.
And the revised code:
(function() {
var app = angular.module('myApp', ['ui.router']);
app.controller('mainController', [
'$scope',
'$state',
function($scope, $state) {
$scope.medication = {};
$scope.openSesame = false;
$scope.$on('$stateChangeSuccess',function(event, toState){
$scope.openSesame = toState.params.showSection;
});
$scope.triggerMe = function() {
alert('yes');
};
}
]);
app.config([
'$stateProvider',
'$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('medications', {
url: '/medications',
template: '<div>{{openSesame}}</div>',
controller: 'mainController',
params: {
showSection: false
}
})
.state('medications.add', {
url: '/add',
template: '<div>{{openSesame}}</div>',
controller: 'mainController',
params: {
showSection: true
},
});
$urlRouterProvider.otherwise('medications');
}
]);
}());
Click your buttons medication and medication add to see the value change.
The callback of $stateChangeSuccess, you have access toState, fromState. Or check current state name
$rootScope.$on("$stateChangeSuccess", function() {
if ($state.current.name == "medications.add") {
$scope.openSesame = true;
}
console.log($scope.openSesame);
});

Dynamically switch ng-include between controllers

I have the following bit of code for my navigation that I want to update dynamically between pages.
<nav ng-include="menuPath"></nav>
Here is my app and routing set up
var rxApp = angular.module('ehrxApp', ['ngRoute']);
// configure our routes
rxApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'mainController',
templateUrl: '/content/views/index.html'
})
.when('/census', {
templateUrl: '/content/views/admission/census.html',
controller: 'censusController'
})
.when('/messages', {
templateUrl: '/content/views/account/messages.html',
controller: 'messagesController'
})
.when('/profile', {
templateUrl: '/content/views/account/profile.html',
controller: 'profileController'
})
});
In my main controller I set the menuPath value here:
rxApp.controller('mainController', function (userService, $scope, $http) {
evaluate_size();
$scope.menuPath = "/content/views/index.menu.html";
});
rxApp.controller('censusController', function ($scope, $http, $sce, censusService) {
$scope.menuPath = "/content/views/admission/census.menu.html";
evaluate_size();
});
When the page switches to the census view it should change the menu. What happens though is the first page loads the main menu, then no matter what other page you go to the menu never updates.
I imagine this problem has something to do with a primitive values and prototypical inheritance between child scopes, but would need to see more of your html to determine that. Without that, I propose an alternative way that may solve your problem and keep the config all in one place.
$routeProvider will accept variables and keep them on the route, even if angular doesn't use them. so we modify your routing by including the menuPath like so:
var rxApp = angular.module('ehrxApp', ['ngRoute']);
// configure our routes
rxApp.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'mainController',
templateUrl: '/content/views/index.html',
menuPath: '/content/views/index.menu.html'
})
.when('/census', {
templateUrl: '/content/views/admission/census.html',
controller: 'censusController',
menuPath: '/content/views/admission/census.menu.html'
})
.when('/messages', {
templateUrl: '/content/views/account/messages.html',
controller: 'messagesController'
})
.when('/profile', {
templateUrl: '/content/views/account/profile.html',
controller: 'profileController'
})
});
Remove setting $scope.menuPath from each controller, then finally add a watch on rootScope that will change the menuPath on $routeChangeSuccess
rxApp.run(['$rootScope', function ($rootScope) {
$rootScope.$on('$routeChangeSuccess', function(event, current) {
if (current && current.$$route && current.$$route.menuPath) {
$rootScope.menuPath = current.$$route.menuPath;
} else {
$rootScope.menuPath = '';
}
});
}]);

Resources