Modularize AngularJS App Using UI-Router - angularjs

I'm trying to modularize a large AngularJS app (1.4.8) that is using UI-Router.
The current structure is like this:
transactionApp.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function ($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider
.state('root', {
url: '/transaction',
views: {
'header': {
templateUrl: '/Partials/Shells/Header/header-partial.html',
controller: 'headerController',
resolve: {
headerItems: ['$http', function ($http) {
var data = {};
data["__RequestVerificationToken"] = $('[name=__RequestVerificationToken]').val();
if (dataForLayout.IsLoggedIn) {
return $http({
method: 'POST',
url: '/myaccount/GetHeaderAccountInfo',
data: data
});
}
}]
}
},
'footer': {
templateUrl: '/Partials/Shells/Footer/footer-partial.html',
controller: 'footerController'
},
'mainPanel': {
templateUrl: '/Partials/Shells/Transaction/transaction-partial.html',
controller: 'mainPanelController'
},
'successPanel': {
templateUrl: '/Partials/Shells/Transaction/transaction-success-panel.html',
controller: 'successPanelController'
}
}
});
$urlRouterProvider.otherwise('/transaction');
// Enable HTML5Mode for #-urless
$locationProvider.html5Mode(true);
}]);
The part I want to modularize is "mainPanel." The mainPanel consists of step 1, step 2, step 3, and the final review/submit page. I'd also like to separate pop-up modals if possible/beneficial. The steps, review page, and modals are dependent on each other.
The URL has to stay "/transaction" no matter which step the user is in.
What I'm envisioning is having the parent as "mainPanel" that connects the sub modules and having sub modules that are "step 1," step 2," and so on.
I've read some articles, but can't seem to find one that talks about further modularizing a module.

Related

trying to go from one form to another in angularjs

I am making a project on my own to practice what I've learned about MEAN stack. In the project I want the user to fill in a form and after it is saved in the database the system to take a use to a second form to fill it in etc. I am angularjs for the front end, and within it I am using ui.route. For some reason my program doesn't go to the second program. I already read about other people with the same problem and I can't find what is wrong with my algorithm. Every form works well by itself or when I Make a call from the toolbar.
Frontend.js
angular
.module('authApp',['auth0', 'angular-storage', 'angular-jwt', 'ngMaterial', 'ui.router',
'AdminUser', 'appProfile', 'appToolbar', 'Mod-Company', 'ModShow'])
.config(function($provide, authProvider, $urlRouterProvider, $stateProvider, $httpProvider, jwtInterceptorProvider,$mdThemingProvider){
/* $mdThemingProvider.theme('docs-dark'); */
$mdThemingProvider.theme('default')
.dark();
$mdThemingProvider.alwaysWatchTheme(true);
authProvider.init({
domain: 'workflowjobs.auth0.com',
clientID: 'SjzgRRh3w4ZEFRGLdglpJYvCPCkM189w'
});
jwtInterceptorProvider.tokenGetter = function(store) {
return store.get('id_token');
}
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'components/home/home.html'
})
.state('company', {
url: '/company',
templateUrl: 'components/company/company.html'
})
.state('singlecompany', {
url: '/singlecompany',
templateUrl: 'components/singlecompany/singlecompany.html'
})
.state('show', {
url: '/show',
templateUrl: 'components/show/show-form.html'
})
.state('ticket', {
url: '/ticket',
templateUrl: 'components/ticket/ticket.html'
})
.state('useradmin', {
url: '/useradmin',
templateUrl: 'components/useradmin/useradmin.html'
})
.state('user', {
url: '/user',
templateUrl: 'components/user/user.html'
})
.state('profile', {
url: '/profile',
templateUrl: 'components/profile/profile.html',
controller: 'profileController',
controllerAs: 'user'
});
From the form I use the controller I need, display the form to be filled in by the user and then I call addcompany() after the user click on the button to save the document on the mongodb database.
<section class="table" ng-controller="CompanyCtrl">
<form name="CompanyForm">
...
<input class="form-control" ng-model="company.name" size="40">
...
<p><md-button class="md-raised md-primary md-hue-1" ng-click="addcompany()" aria-label="next">
Now in this code is where I have the problem. the $location.path('/adminuser') doesn't work:
var app = angular.module('Mod-Company', []);
app.controller('CompanyCtrl', ['$scope', '$http',
function($scope,$http){
var refresh = function() {
$http.get('http://localhost:3001/api/company').success(function(response){
$scope.companylist = response;
$scope.company = "";
});
};
refresh();
$scope.addcompany = function(){
$http.post('http://localhost:3001/api/company', $scope.company).success(function(response) {
refresh();
$location.path('/useradmin');
});
$location.path('/useradmin');
};
Instead of using $location.path('/useradmin'); try $state.go('useradmin');.
If it is still not working, it will be easier to help you if you could share your code in a https://jsbin.com or https://plnkr.co

change angular state according to the URL parameter

Hi in my app I have two states called hello and createHello
Modules related to thees two states are given below.
createHello Module
(function(module){
'use strict';
module.config(['$stateProvider',
function($stateProvider) {
$stateProvider.state('createHello', {
url: '/hello/create',
templateUrl: 'app/createHello/createHello.html',
controller: 'createHello'
});
}
]);
})(angular.module('createHello', ['header', 'ui.router', 'timeliner','common']));
hello Module
(function (module) {
'use strict';
module.config(['$stateProvider',
function ($stateProvider) {
$stateProvider.state('hello', {
url: '/hello/{id}',
templateUrl: 'app/hello/hello.html',
controller: 'hello',
resolve: {
.....
}
});
}
]);
})(angular.module('hello', ['header', 'ui.router', 'helloTimer', 'logger', 'timeliner', 'common']));
Any url pattern of /hello/xxxx will go to the hello state. I want this specific url (/hello/create) to go to the createHellostate. At the moment it will also go to the hello state. Any advice on how to solve this issue?
In this case you should used nested states.
module.config(['$stateProvider',
function($stateProvider) {
$stateProvider
.state('hello', {
url: '/hello',
abstract: true,
template: '<ui-view/>'
})
.state('hello.create', {
url: '/create',
templateUrl: 'app/createHello/createHello.html',
controller: 'createHello'
})
.state('hello.display', {
url: '/:id',
templateUrl: 'app/hello/hello.html',
controller: 'hello'
});
}
]);
Note that routing is done on "first match", so you will need to have your /hello/create route declared before the /hello/:id route.
You can read more on how nesting works here:
https://github.com/angular-ui/ui-router/wiki/Nested-States-&-Nested-Views
In the example above I used an abstract parent state.

Separate common parts of controller into a common controller

I'm developing an web app using AngularJS with uiRouter. I developed my route configuration as follows:
(function () {
'use strict';
var module = angular.module('app', ['ngMaterial', 'ui.router']);
function Config($urlRouterProvider, $stateProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider.state('Home', {
url: '/',
templateUrl: 'Partials/homeview.html',
controller: 'homeCtrl'
}).state('Table', {
url: '/tableview',
templateUrl: 'Partials/tableview.html',
controller: 'tableCtrl'
}).state('List', {
url: '/listview',
templateUrl: 'Partials/listview.html',
controller: 'listCtrl'
}).state('New', {
url: '/new',
templateUrl: 'Partials/new.html',
controller: 'newCtrl'
}).state('Edit', {
url: '/edit/:index',
templateUrl: 'Partials/edit.html',
controller: 'editCtrl'
});
}
Config.$inject = ["$urlRouterProvider", "$stateProvider"];
module.config(Config);
}());
The thing in some controller passed to the view the code is duplicated, so I would like to know if there is a way to pass 2 controllers to the view at the same time or if there is a way to create a separate file with that specific part of the duplicated controller and pass it as Dependency Injection in the desired controllers.
You can't have two controllers linked to a uiRouter route. But you could certainly make a service or factory that includes your universal functionality. (See angular.service vs angular.factory for more research.)
var app = angular.module('app',[])
app.service('myFunctions',function() {
this.addNumbers = function(a,b) {
// calculate some stuff
return a+b;
}
}
app.controller('myController',function(myFunctions){
myFunctions.addNumbers(2,2); // 4
})

Redirect after login AngularJS Meteor

I'm trying to redirect after login to a specific page in Meteor using AngularJS. But somehow it is not working. After login Meteor.user() is returning null. Because of this every time it is routing to messages page only. I have seen this example from one of the forums and developed on top of that.
angular.module("jaarvis").run(["$rootScope", "$state", "$meteor", function($rootScope, $state, $meteor) {
$meteor.autorun($rootScope, function(){
if (! Meteor.user()) {
console.log('user');
if (Meteor.loggingIn()) {
console.log('loggingIn ' + Meteor.user()); -- returning null
if(Meteor.user()) {
$state.go('onlineusers');
} else {
//On login
$state.go("messages");
}
}
else{
console.log('login');
$state.go('login');
}
}
});
}]);
Routes declared as below.
angular.module('jaarvis').config(['$urlRouterProvider', '$stateProvider', '$locationProvider',
function($urlRouterProvider, $stateProvider, $locationProvider){
$locationProvider.html5Mode(true);
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'login.ng.html',
controller: 'LoginCtrl'
})
.state('onlineusers',{
url: '/onlineusers',
templateUrl: 'client/onlineusers/onlineusers.ng.html',
controller: 'OnlineUsersCtrl'
})
.state('messages', {
url: '/messages',
templateUrl: 'client/chats.ng.html',
controller: 'ChatCtrl'
})
});
$urlRouterProvider.otherwise("/messages");
}]);
Logging using below snippet of code.
<meteor-include src="loginButtons"></meteor-include>
Michael is probably right about the root cause of the problem, but I think that a better alternative is provided by the the authentication methods of Angular-Meteor.
What you are going to want to do is to force the resolution of a promise on the route. From the Angular-Meteor docs (i.e. a general example...):
// In route config ('ui-router' in the example, but works with 'ngRoute' the same way)
$stateProvider
.state('home', {
url: '/',
templateUrl: 'client/views/home.ng.html',
controller: 'HomeController'
resolve: {
"currentUser": ["$meteor", function($meteor){
return $meteor.waitForUser();
}]
}
});
Your specific code would look something like:
angular.module('jaarvis').config(['$urlRouterProvider', '$stateProvider', '$locationProvider',
function($urlRouterProvider, $stateProvider, $locationProvider){
$locationProvider.html5Mode(true);
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'login.ng.html',
controller: 'LoginCtrl'
})
.state('onlineusers',{
url: '/onlineusers',
templateUrl: 'client/onlineusers/onlineusers.ng.html',
controller: 'OnlineUsersCtrl',
resolve: {
"currentUser": ["$meteor", function($meteor){
return $meteor.waitForUser();
}]
}
})
.state('messages', {
url: '/messages',
templateUrl: 'client/chats.ng.html',
controller: 'ChatCtrl',
resolve: {
"currentUser": ["$meteor", function($meteor){
return $meteor.waitForUser();
}]
}
})
});
$urlRouterProvider.otherwise("/messages");
}]);
And then on your ChatCtrl and OnlineUsersCtrl controllers, you would add currentUser as one of the variables to inject, like:
angular.module("rootModule").controller("ChatCtrl", ["$scope", "$meteor", ...,
function($scope, $meteor, ..., "currentUser"){
console.log(currentUser) // SHOULD PRINT WHAT YOU WANT
}
]);
You might also want to consider the $meteor.requireUser() promise as well, and then send the user back to the login page if the promise gets rejected. All of this is documented very well on the angular-meteor website.
Good luck!
It could be that the user object hasn't loaded yet. You can try:
if ( Meteor.userId() ) ...
instead

How to make tabs in angularJS have separate controllers?

Right now i am using routeProvider to change between views which works awesome. But now i want to create a view which contains 4 different tabs which should contain 4 different controllers. ive read here that it could be done with stateProvider:
Angular ui tab with seperate controllers for each tab
here is my code:
var WorkerApp = angular.module("WorkerApp", ["ngRoute", 'ngCookies', "ui.bootstrap", "ngGrid", 'ngAnimate', 'ui.router']).config(function ($routeProvider, $stateProvider) {
$routeProvider.
when('/login', {
templateUrl: 'Home/Template/login', resolve: LoginCtrl.resolve
})
.when('/register', { templateUrl: 'Home/Template/register', resolve: RegisterCtrl.resolve })
.when('/', { templateUrl: 'Home/Template/main', resolve: MainCtrl.resolve })
.when('/profile', { templateUrl: 'Home/Template/profile', controller: "ProfileController" })
.when('/contact', { templateUrl: 'Home/Template/contact', controller: "ContactController" })
$stateProvider.state('tabs', {
abstract: true,
url: '/profile',
views: {
"tabs": {
controller: "ProfileController",
templateUrl: 'Home/Template/profile'
}
}
}).state('tabs.tab1', {
url: '/profile', //make this the default tab
views: {
"tabContent": {
controller: "ProfileController",
templateUrl: 'Home/Template/profile'
}
}
})
.state('tabs.tab2', {
url: '/tab2',
views: {
"tabContent": {
controller: 'Tab2Ctrl',
templateUrl: 'tab2.html'
}
}
});
});
but i cant get it really to work because default of routeprovider is set to send over to work because my routeprovider is sending over to "/" on default, which makes "/tabs" invalid. so i cant actully figure out if it is possible to switch to states on specific url. Or change state on specific URL in routeProvider?
I can't tell you for sure exactly what's wrong with the code you've provided, but I'm using Angular UI-Router with the same use case you described, and it's working for me. Here's how I have it configured and how it's different from your configuration:
I don't use $routeProvider at all (none of your $routeProvider.when statements). I'm pretty sure you should not be using $routeProvider since you're using $stateProvider.
I have one use of the $urlRouterProvider with an 'otherwise' statement to specify a default URL:
$urlRouterProvider.otherwise("/home");
My calls to $stateProvider.state is a little different from yours. Here's the one for the parent view of the tabs:
$stateProvider.state('configure', {
url: "/configure",
templateUrl: 'app/configure/configure.tpl.html',
controller: 'ConfigureCtrl'
});
Here's an example of the child state (really the same except for the state name being parent.child format, which you already have in your code; and I added a resolve block but you could have that on the parent as well):
$stateProvider.state('configure.student', {
url: "/student",
templateUrl: 'app/configure/student/configure.student.tpl.html',
controller: 'ConfigureStudentCtrl',
resolve: {
storedClassCode: function($q, user, configureService) {
return configureService.loadMyPromise($q, user);
}
}
});
Also, I'm using version 0.2.8 of Angular UI-Router with version 1.2.9 of Angular. I think this would work with any version of Angular 1.2.0 or later.

Resources