angularFire route resolution - javascript

I'd like to have my angularFire collection resolve on route loading. Something like:
App.config ($routeProvider, angularFireProvider) ->
$routeProvider.when '/test',
templateUrl: 'views/test.html'
controller: 'TestCtrl'
resolve: angularFireProvider.resolve 'testItems'
Is it possible to do this?

I'm not exactly sure why you want the collection to resolve on route loading, as opposed to in the controller - could you elaborate? For example, the following would work too:
App.config ($routeProvider, angularFireProvider) ->
$routeProvider.when '/test',
controller: 'TestCtrl'
function TestCtrl($scope, angularFire) {
angularFire("https://<example>.firebaseio.com", $scope, "collection").
then(function() {
// The collection has been resolved and available in $scope.collection
});
}
Is it mainly a matter syntactic convenience or am I missing functionality you want in the above?
Update: For the value to be resolved before the $routeChangeSuccess event is fired:
App.config(['$routeProvider', 'angularFire', function($routeProvider, angularFire) {
$routeProvider.when("/test", {
templateUrl: 'views/test.html'
controller: 'TestCtrl',
resolve: {collection: angularFire("https://<example>.firebaseio.com")}
});
}]);
function TestCtrl(collection) {
// collection has already been resolved to its value.
}

Related

angular resolve reload when same route reloading

How can I reload the Angular resolve with the reload?
My code :
.when('/dashbord', {
title: 'dashbord',
templateUrl: 'views/dashbord.php',
controller: 'dashbordController',
resolve: {
getDashbord: function (getDashbordService) {
return getDashbordService;
}
}
})
Reload function :
app.run(['$rootScope', '$route', '$templateCache', function ($rootScope, $route, $templateCache) {
$rootScope.changeRoute = function(){
var currentPageTemplate = $route.current.templateUrl;
$templateCache.remove(currentPageTemplate);
$route.reload();
};
}]);
The above function reload only the view. It doesn't reload the resolve.
How can i do it in angular ?
I created plunker for you that shows that
$route.reload()
fires resolve on state
I know this is a late answer, but one thing to keep in mind is that Angular services are singletons -- which means if you define your resolve function as a service (esp. one that makes an $http request), you will get the same results each time the route resolves.
For example, this uses an Angular service that makes an $http request, and won't make a new $http request on $route.reload():
angular.module('myApp').factory('getDashboardService', ['$http', function getDashboardService($http) {
return $http.get('/path/to/resource'); // returns a promise
}]).config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/dashboard', {
title: 'dashboard',
templateUrl: 'views/dashboard.php',
controller: 'DashboardController',
resolve: {
getDashbord: 'getDashboardService' // refers to an Angular service
}
});
}]);
...but this will, because it is not an injected service:
angular.module('myApp').config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/dashboard', {
title: 'dashboard',
templateUrl: 'views/dashboard.php',
controller: 'DashboardController',
resolve: {
getDashboard: ['$http', function($http) {
return $http.get('/path/to/resource');
}]
}
});
});
Here is a JSFiddle: https://jsfiddle.net/sscovil/77ys9hz5/

Angularjs: Inject Service in app.config such that to safeguard against minification

I am trying to inject a service in app.config as illustrated in Inject service in app.config. However, minification breaks the app. How to overcome this?
This doesn't work with minification:
app.config(['$routeProvider',function ($routeProvider) {
$routeProvider
.when('/',
{
templateUrl: "partials/editor.html",
controller: "AppCtrl",
resolve: {
//Following method doesn't work with minification
data: getData
}
})
function getData (dbService) {
return dbService.getData();
}
}]);
Please note the following code doesn't work: (Typescript does not allow compilation)
['dbService',function getData(dbService){
return dbService.getData();
}]
In order to safeguard against minification, you need to annotate (see Dependency Annotation here) the data function like you did with the config function.
There are two ways to do this.
1.
Instead of passing a function, pass an array with the names of the dependencies and the function
app.config(['$routeProvider',function ($routeProvider) {
$routeProvider
.when('/',
{
templateUrl: "partials/editor.html",
controller: "AppCtrl",
resolve: {
//annotate this to prevent against minification
data: ['dbService', getData]
}
})
function getData (dbService) {
return dbService.getData();
}
}]);
2.
Add your dependencies to a $inject property on your function
app.config(['$routeProvider',function ($routeProvider) {
$routeProvider
.when('/',
{
templateUrl: "partials/editor.html",
controller: "AppCtrl",
resolve: {
//function annotated below
data: getData
}
})
//annotate this function with $inject so proper dependencies injected after minification
getData.$inject = ['dbService'];
function getData (dbService) {
return dbService.getData();
}
}]);

how do I set up my angularjs controller

I'm just messing around with angular a bit and I built a simple task API. This api has assigned and accepted tasks. Now when building the app I have these routes:
TaskManager.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/:username/assigned-tasks', {
templateUrl: 'app/partials/assigned-tasks.html',
controller: 'TaskController'
}).
when('/:username/accepted-tasks', {
templateUrl: 'app/partials/assigned-tasks.html',
controller: 'TaskController'
}).
otherwise({
redirectTo: '/'
});
}]);
And here is the task controller I started building and then realized this was not going to work
TaskManager.controller('TaskController', ['$scope', 'AssignedTasksService', function($scope, AssignedTasksService)
{
$scope.tasks = [];
loadAssignedTasks();
function applyRemoteData( Tasks ) {
$scope.tasks = Tasks;
}
function loadAssignedTasks() {
AssignedTasksService.getAssignedTasks()
.then(
function( tasks ) {
applyRemoteData( tasks );
}
);
}
}]);
The getAssignedTasks funciton is just a function that runs a http get request to the api url and either returns and error or the api data
now as you can see the assigned tasks are automatically loaded once it hits the TaskController which is obviously a problem since I need to also be able to get accepted tasks. Now do I need to create a separate controller for accepted tasks or is there a way for maybe me to check the url from the controller and from there I can decide if I want to run the loadAssignedTasks function or the loadAcceptedTasks (which I haven't created yet). but it would just do the same thing as the loadAssignedTasks function but for the accepted tasks
As mentioned in the comments there are multiple ways to solve. All depending on current use case. But you should probably use seperate controllers to solve this problem. Also inject the data(tasks) into the controller rather than fetching them inside the controller. Consider the following example:
var resolveAssignedTasks = function(AssignedTasksService) {
return AssignedTasksService.getAssignedTasks();
};
var resolveAcceptedTasks = function(AcceptedTasksService) {
return AcceptedTasksService.getAcceptedTasks();
};
TaskManager.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/:username/assigned-tasks', {
templateUrl: 'app/partials/assigned-tasks.html',
controller: 'TaskController',
resolve: {
tasks: resolveAssignedTasks
}
}).
when('/:username/accepted-tasks', {
templateUrl: 'app/partials/assigned-tasks.html',
controller: 'TaskController',
resolve: {
tasks: resolveAssignedTasks
}
}).
otherwise({
redirectTo: '/'
});
}]);
Controllers:
TaskManager.controller('AssignedTaskController', ['$scope', 'tasks', function($scope, tasks)
{
$scope.tasks = tasks;
}]);
TaskManager.controller('AcceptedTaskController', ['$scope', 'tasks', function($scope, tasks)
{
$scope.tasks = tasks;
}]);
You could also by doing this use a single controller by merging the resolveFunctions into one function that returns the appropriate tasks depending on the current route. Hope this helps.

opening a modal in a route in AngularJS with angular-ui-bootstrap

I am trying to do what was essentially answered here Unable to open bootstrap modal window as a route
Yet my solution just will not work. I get an error
Error: [$injector:unpr] Unknown provider: $modalProvider <- $modal
My app has the ui.bootstrap module injected - here is my application config
var app = angular.module('app', ['ui.router', 'ui.bootstrap','ui.bootstrap.tpls', 'app.filters', 'app.services', 'app.directives', 'app.controllers'])
// Gets executed during the provider registrations and configuration phase. Only providers and constants can be
// injected here. This is to prevent accidental instantiation of services before they have been fully configured.
.config(['$stateProvider', '$locationProvider', function ($stateProvider, $locationProvider) {
// UI States, URL Routing & Mapping. For more info see: https://github.com/angular-ui/ui-router
// ------------------------------------------------------------------------------------------------------------
$stateProvider
.state('home', {
url: '/',
templateUrl: '/views/index',
controller: 'HomeCtrl'
})
.state('transactions', {
url: '/transactions',
templateUrl: '/views/transactions',
controller: 'TransactionsCtrl'
})
.state('login', {
url: "/login",
templateUrl: '/views/login',
controller: 'LoginCtrl'
})
.state('otherwise', {
url: '*path',
templateUrl: '/views/404',
controller: 'Error404Ctrl'
});
$locationProvider.html5Mode(true);
}])
I have reduced my controller to the following:
appControllers.controller('LoginCtrl', ['$scope', '$modal', function($scope, $modal) {
$modal.open({templateUrl:'modal.html'});
}]);
Ultimately, what I am hoping to achieve is when login is required not actually GO to the login page, but bring up a dialog.
I have also tried using the onEnter function in the ui-router state method. Couldn't get this working either.
Any ideas?
UPDATE
Ok - so as it turns out, having both ui-bootstrap.js AND ui-bootstrap-tpls breaks this - After reading the docs I thought you needed the templates to work WITH the ui-bootstrap. though it seems all the plunkers only load in the ..tpls file - once I removed the ui-bootstrap file my modal works...Am i blind? or doesn't it not really say which one you need in the docs on github? -
Now i just need to figure out how to prevent my url from actually going to /login, rather than just show the modal :)
update 2
Ok, so by calling $state.go('login') in a service does this for me.
Hi I had a hard time getting through the similar problem.
However, I was able to resolve it.
This is what you would probably need.
app.config(function($stateProvider) {
$stateProvider.state("managerState", {
url: "/ManagerRecord",
controller: "myController",
templateUrl: 'index.html'
})
.state("employeeState", {
url: "empRecords",
parent: "managerState",
params: {
empId: 0
},
onEnter: [
"$modal",
function($modal) {
$modal.open({
controller: "EmpDetailsController",
controllerAs: "empDetails",
templateUrl: 'empDetails.html',
size: 'sm'
}).result.finally(function() {
$stateProvider.go('^');
});
}
]
});
});
Click here for plunker. Hope it helps.
I'm working on something similar and this is my solution.
HTML code
<a ui-sref="home.modal({path: 'login'})" class="btn btn-default" ng-click="openModal()">Login</a>
State configuration
$stateProvider
// assuming we want to open the modal on home page
.state('home', {
url: '/',
templateUrl: '/views/index',
controller: 'HomeCtrl'
})
// create a nested state
.state('home.modal', {
url: ':path/'
});
Home controller
//... other code
$scope.openModal = function(){
$modal.open({
templateUrl: 'path/to/page.html',
resolve: {
newPath: function(){
return 'home'
},
oldPath: function(){
return 'home.modal'
}
},
controller: 'ModalInstanceController'
});
};
//... other code
Finally, the modal instance controller.
This controller synchronizes the modal events (open/close) with URL path changes.
angular.module("app").controller('ModalInstanceController', function($scope, $modalInstance, $state, newPath, oldPath) {
$modalInstance.opened.then(function(){
$state.go(newPath);
});
$modalInstance.result.then(null,function(){
$state.go(oldPath);
});
$scope.$on('$stateChangeSuccess', function () {
if($state.current.name != newPath){
$modalInstance.dismiss('cancel')
}
});
});
You may create a state with the same templateUrl and controller as your page where you want to show the modal, adding params object to it
$stateProvider
.state('root.start-page', {
url: '/',
templateUrl: 'App/src/pages/start-page/start-page.html',
controller: 'StartPageCtrl'
})
.state('root.login', {
url: '/login',
templateUrl: 'App/src/pages/start-page/start-page.html',
controller: 'StartPageCtrl',
params: {
openLoginModal: true
}
})
And in controller of the page, use this parameter to open the modal
.controller("StartPageCtrl", function($scope, $stateParams) {
if ($stateParams.openLoginModal) {
$scope.openLoginModal();
}
I found a handy hint to get this working. There are probably caveats, but it works for me. You can pass a result still but I have no need for one.
Using finally instead of the then promise resolve sorted this for me. I also had to store the previous state on rootScope so we knew what to go back to.
Save previous state to $rootScope
$rootScope.previousState = 'home';
$rootScope.$on('$stateChangeSuccess', function(ev, to, toParams, from, fromParams){
$rootScope.previousState = from.name;
})
State using onEnter
$stateProvider.state('contact', {
url: '/contact',
onEnter: function ($state, $modal, $rootScope){
$modal.open({
templateUrl: 'views/contact.html',
controller: 'ContactCtrl'
}).result.finally(function(){
$state.go($rootScope.previousState);
})
}
});

$routeProvider - Injecting same dependency for all routes

The following code:
$routeProvider
.when("/page1", { controller: "MyController", resolve: {Strategy: "StrategyOne"}})
waits for the Strategy dependency to be resolved before to instantiate the controller "MyController".
In my application I have a function which returns a promise, which when resolved, gives the current user. Let's called that function Authentication.currentUser()
I would like all the pages of my app to wait for that promise to be resolved before to render a page. I could happily add a line for each route declaration but I would rather avoid duplication.
I have a controller called 'MainCtrl' which is called for all pages thanks to this line in my template:
<html ng-app="clientApp" ng-controller="MainCtrl">
I think one possible way to address this would be if it was possible to specify Authentication.currentUser() as a dependency of "MainCtrl" at the controller level (not at the route level because this dependency does not depend on a particular route).
Thanks for your help guys!
For those who want to address this with the standard $routeProvider, this is what I came out with:
$rootScope.$on('$routeChangeStart', function (event, next, current) {
if (!next.resolve){ next.resolve = {} }
next.resolve.currentUser = function(Authentication){
return Authentication.currentUser();
};
});
If you can move from the default router, to ui-router, then you can do this with nested states. Just copying the example from https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views#inherited-resolved-dependencies :
$stateProvider.state('parent', {
resolve:{
resA: function(){
return {'value': 'A'};
}
},
controller: function($scope, resA){
$scope.resA = resA.value;
}
})
.state('parent.child', {
resolve:{
resB: function(resA){
return {'value': resA.value + 'B'};
}
},
controller: function($scope, resA, resB){
$scope.resA2 = resA.value;
$scope.resB = resB.value;
}

Categories

Resources