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

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)
]);

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) {
...
});
}

Angular ui router persisting $stateParams

I've defined a params object on my parent state and want to assign values to the properties, on child states, and have that value persist to other states. When I navigate to child states I see the $stateParams.property but after assigning a value to $stateParams.property the value is not persisting to the next sibling state.
.state({
name: 'parent',
url: '/parent',
templateUrl: 'app/parent.html',
controller: 'parentController',
controllerAs: 'vm',
resolve: {
user: function(){
return { user: {} };
},
//regionsCountriesInfo: ['$stateParams', function($stateParams){
// return $stateParams.regionsCountriesInfo;
//}],
// edit
regionsCountriesInfo: function(){
return { value: [] };
}
},
children: [
{
name: 'region',
url: '/region',
templateUrl: 'app/region.html',
controller: 'regionController',
controllerAs: 'vm',
ncyBreadcrumb: {
label: 'Regions',
parent: 'parent'
},
resolve: {
user: function(user) {
return user;
},
// edit
regionsCountriesInfo: function(regionsCountriesInfo) {
return regionsCountriesInfo;
}
}
},
{
name: 'user',
url: '/user',
templateUrl: 'app/user.html',
controller: 'userController',
controllerAs: 'vm',
ncyBreadcrumb: {
label: 'Users',
parent: 'parent'
},
resolve: {
user: function(user) {
return user;
},
// edit
regionsCountriesInfo: function(regionsCountriesInfo) {
return regionsCountriesInfo;
}
}
},
// regionController
regionController.$inject = [
'$scope',
'$translate',
'$uibModal',
'$state',
'$stateParams',
'$rootScope',
'regionsCountriesInfo'
];
function regionController($scope, $translate, $uibModal, $state, $stateParams, $rootScope, regionsCountriesInfo) {
...
vm.selectedRegions = [];
...
vm.selectedRegions.push(region)
console.log('regionController regionsCountriesInfo');
console.log(regionsCountriesInfo);
regionsCountriesInfo = vm.selectedRegions;
console.log('regionController regionsCountriesInfo');
console.log(regionsCountriesInfo);
// regionController console output
regionController regionsCountriesInfo
undefined
regionController regionsCountriesInfo
[Object]
// userController
userController.$inject = [
'$translate',
'$uibModal',
'$state',
'$scope',
'$timeout',
'$stateParams',
'$rootScope',
'regionsCountriesInfo'
];
function userController($translate, $uibModal, $state, $scope, $timeout, $stateParams, $rootScope, regionsCountriesInfo) {
...
console.log('userController regionsCountriesInfo');
console.log(regionsCountriesInfo);
// userController console output
userController regionsCountriesInfo
undefined
Why is $stateParams.regionsCountriesInfo empty in the user state when I assigned a value to it in the region sibling state?
You need to use resolve in the parent state as $stateparams only contains params registered with that state.
state({
name: 'parent',
url: '/parent',
templateUrl: 'app/parent.html',
controller: 'parentController',
controllerAs: 'vm',
resolve: {
regionsCountriesInfo: ['$stateParams', function($stateParams){
return $stateParams.regionsCountriesInfo;
}]
}
i think each child create isolated varibles , did you try to repass it to child in routing ?
I guess the problem was that I needed to use a regular resolve object, as the value I needed to persist wasn't in $stateParams to begin with i.e., it was defined in the regionController. See edit above.

AngularJS UI router: Block view

Right now i am making an AngularJS+UI router install application. But i have a problem, the problem is, that i want to disable access to the views, associated with the install application. I want to do it in resolve in the state config.
But the problem is i need to get the data from a RESTful API, whether the application is installed or not. I tried making the function, but it loaded the state before the $http.get request was finished.
Here was my code for the resolve function:
(function() {
var app = angular.module('states', []);
app.run(['$rootScope', '$http', function($rootScope, $http) {
$rootScope.$on('$stateChangeStart', function() {
$http.get('/api/v1/getSetupStatus').success(function(res) {
$rootScope.setupdb = res.db_setup;
$rootScope.setupuser = res.user_setup;
});
});
}]);
app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/404");
$stateProvider.state('db-install', {
url: "/install/db",
templateUrl: 'admin/js/partials/db-install.html',
controller: 'DBController',
resolve: {
data: function($q, $state, $timeout, $rootScope) {
var setupStatus = $rootScope.setupdb;
var deferred = $q.defer();
$timeout(function() {
if (setupStatus === true) {
$state.go('setup-done');
deferred.reject();
} else {
deferred.resolve();
}
});
return deferred.promise;
}
}
})
.state('user-registration', {
url: "/install/user-registration",
templateUrl: "admin/js/partials/user-registration.html",
controller: "RegisterController"
})
.state('setup-done', {
url: "/install/setup-done",
templateUrl: "admin/js/partials/setup-done.html"
})
.state('404', {
url: "/404",
templateUrl: "admin/js/partials/404.html"
});
}]);
})();
EDIT:
Here is what my ajax call returns:
Try this way:
$stateProvider.state('db-install', {
url: "/install/db",
templateUrl: 'admin/js/partials/db-install.html',
controller: 'DBController',
resolve: {
setupStatus: function($q, $state, $http) {
return $http.get('/api/v1/getSetupStatus').then(function(res) {
if (res.db_setup === true) {
$state.go('setup-done');
return $q.reject();
}
return res;
});
}
}
})
Then inject setupStatus in controller:
.state('setup-done', {
url: "/install/setup-done",
templateUrl: "admin/js/partials/setup-done.html",
controller: ['$scope', 'setupStatus', function ($scope, setupStatus) {
$scope.setupdb = setupStatus.db_setup;
$scope.setupuser = setupStatus.user_setup;
}]
})

Re-use URI in many angular UI-Router state

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

unable to open a modal with angular and ui.routes

I am trying to follow this example to show a bootstrap modal on a certain state. It works fine without a modal (so the state config should be ok). All needed dependencies (ie angular bootstrap) should be available.
when I do a console.debug($stateParams) before $modal.open I get the correct data, within the $modal.open-method however the stateParams from the last state are returned (the state I am coming from)
Any hints?
EDIT
the relevant state cfg:
.state('publications.view', {
parent: 'publications.productSelection',
url: '/{productSlug:[a-zA-Z0-9-]+}/{docID:[0-9]+}_{slug:[a-zA-Z0-9-]+}',
onEnter: ['restFactory', '$state', '$stateParams', '$modal',
function(restFactory, $state, $stateParams, $modal) {
console.debug($stateParams.docID);
$modal.open({
templateUrl: 'partials/publication.html',
resolve: {
publication: ['restFactory', '$stateParams',
function(restFactory, $stateParams) {
console.debug($state.params);
console.debug($stateParams);
return restFactory.view($stateParams.language, $stateParams.productSlug, $stateParams.docID);
}
]
},
controller: ['$scope', '$sce', 'publication', '$rootScope',
function($scope, $sce, publication, $rootScope) {
$rootScope.pageTitle = publication.data.data.publication.Publication.title;
$scope.publication = $sce.trustAsHtml(publication.data.data.publication.Publication.content);
}
]
});
}
]
});
You can get around this issue by injecting the current $stateParams into the onEnter function, save them as state in some service, and inject that service instead into your modal resolves.
I am adapting the code from here: Using ui-router with Bootstrap-ui modal
.provider('modalState', function($stateProvider) {
var modalState = {
stateParams: {},
};
this.$get = function() {
return modalState;
};
this.state = function(stateName, options) {
var modalInstance;
$stateProvider.state(stateName, {
url: options.url,
onEnter: function($modal, $state, $stateParams) {
modalState.stateParams = $stateParams;
modalInstance = $modal.open(options);
modalInstance.result['finally'](function() {
modalInstance = null;
if ($state.$current.name === stateName) {
$state.go('^');
}
});
},
onExit: function() {
if (modalInstance) {
modalInstance.close();
}
}
});
};
})
Then in your app config section
.config(function($stateProvider, $urlRouterProvider, modalStateProvider) {
modalStateProvider.state('parent.child', {
url: '/{id:[0-9]+}',
templateUrl: 'views/child.html',
controller: 'ChildCtrl',
resolve: {
role: function(Resource, modalState) {
return Resource.get({id: modalState.stateParams.id}).$promise.then(function(data) {
return data;
});
}
}
});
}

Resources