Trying to separate my Controllers and Factories from out of my large app.js file. I learned Angular by putting everything into one file, but now I am trying to organize it all by separating my files.
Originally I had something like this (app.js).
var app = angular.module("app", ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'pages/home.html',
controller: 'HomeController'
})
.when('/home', {
templateUrl: 'pages/home.html',
controller: 'HomeController'
})
.when('/faq', {
templateUrl: 'pages/faq.html',
controller: 'FAQController'
})
.otherwise({
redirectTo: '/unknown'
});
});
app.factory('FAQMethodService', function() {
return {
faqs: [
{
question : "Another FAQ",
answer : "Another FAQ."
},
{
question : "Another FAQ",
answer : "Another FAQ."
},
{
question : "Another FAQ",
answer : "Another FAQ."
},
{
question : "Another FAQ",
answer : "Another FAQ."
}
]
};
});
app.controller('FAQController', function($scope, FAQMethodService) {
$scope.faqList = FAQMethodService.faqs;
$scope.title = "FAQ";
});
app.controller('HomeController', function($scope) {
$scope.title = "Home";
});
For my first step of separation I deleted the section of FAQController from app.js, and made a new file called faqController.js (which I included in my index.html).
angular.module('app').controller('FAQController', ['$scope', '$http', function($scope, FAQMethodService) {
$scope.faqList = FAQMethodService.faqs;
$scope.title = "FAQ";
}]);
When I open my FAQ page I get the $scope.title variable (as I display it), but my FAQMethodService information does not show up.
Question: How can I get my Factory when my Controller is in another file (and can I separate my Factory to another file too)?
When registering things using the array notation, the names and sequence of string arguments must match exactly with the sequence of the constructor function's parameters.
You have a mismatch. You've asked Angular to inject $http into your controller as FAQMethodService
.controller('FAQController', ['$scope', '$http', function($scope, FAQMethodService) {
It should be:
.controller('FAQController', ['$scope', 'FAQMethodService', function($scope, FAQMethodService) {
Related
angular
.module('madkoffeeFrontendApp', [])
.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/articles.html',
controller: 'MainCtrl',
resolve: {
articles: function(articleService,$q) {
// return articleService.getArticles();
return 'boo';
}
}
})
.otherwise({
redirectTo: '/'
});
$locationProvider.html5Mode(true);
});
My above code contains the resolve.
angular.module('madkoffeeFrontendApp')
.controller('MainCtrl', ['$scope',
function($scope, articles) {
console.log(articles);
}]);
When I tried to inject articles in the array as shown below, it gives an error but as far as I know that's the correct way to inject a resolve function:
angular.module('madkoffeeFrontendApp')
.controller('MainCtrl', ['$scope','articles',
function($scope, articles) {
console.log(articles);
}]);
My articles resolve function is not being injected. I tried returning just a string (example: 'boo') as shown to test if articles dependency works or not, and it doesn't i.e. it returns undefined. What could be the reason?
Here's a Plunker to demonstrate the resolve message. As you'll see in the example, it's the same structure as the code you posted and should work fine.
Click the about page to see the resolve message.
http://plnkr.co/edit/FomhxYIra5GI7nm1KpGb?p=preview
Code:
var resolveTestApp = angular.module('resolveTestApp', ['ngRoute']);
resolveTestApp.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl : 'pages/home.html',
controller : 'mainController'
})
.when('/about', {
templateUrl : 'pages/about.html',
controller : 'aboutController',
resolve: {
resolveMessage: function() {
return 'This is the resolve message';
}
}
})
});
resolveTestApp.controller('mainController', function($scope) {
$scope.message = 'Everyone come and see how good I look!';
});
resolveTestApp.controller('aboutController', ['$scope', 'resolveMessage', function($scope, resolveMessage) {
$scope.message = resolveMessage;
}]
);
It may be the version of Angular you're using or a problem when you're minifying your code.
i'm investigating if i can have what the title says.
Here's my thought.
Let's assume that i've got this routes:
.when('/', {
templateUrl : 'partials/homepage.html',
})
.when('/test', {
templateUrl : 'partials/test.html',
})
.when('/page/:pageID', {
templateUrl : 'partials/page.html',
})
.when('/page/single/:pageID', {
templateUrl : 'partials/page-single.html',
})
Until now i had the opportunity to add the templateUrl as also the controller details in the route and everything was working just fine.
Now the app is changed and there is only one controller with all the information needed and must remain one controller. And the routes will be something like that:
.when('/:templateName/:pageID', {
controller: 'myCtrl'
})
Can i set from the controller the template id by getting the templateName parameter? And if so how about the last route example /page/single/:pageID? How can i know that there is a second option in route?
I can take the templateName parameter and see it changing with the $routeChangeSuccess method but i cannot find any way to set the template on the fly.
Any ideas?
One solution could be the following one:
angular.module('myapp', []).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/:templateName/:pageId', {
templateUrl: function(urlattr){
return '/pages/' + urlattr.templateName + '.html';
},
controller: 'YourCtrl'
});
}
]);
From the AngularJs 1.3 Documentation:
templateUrl – {string|function()} – path or function that returns a path to an html template that should be used by ngView.
If templateUrl is a function, it will be called with the following parameters:
Array.<Object> - route parameters extracted from the current $location.path() by applying the current route
I would move your singleton logic from your controller to a service. Since you didn't provide much code below is an example to give you an idea how it could work.
app.config(function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'partials/homepage.html',
controller: 'SingleController'
})
.when('/test', {
templateUrl: 'partials/test.html',
controller: 'SingleController'
})
.when('/page/:pageId', {
templateUrl: 'partials/page.html',
controller: 'SingleController'
});
});
app.provider('appState', function() {
this.$get = [function() {
return {
data: {}
};
}];
});
app.controller('SingleController', function ($scope, appState) {
$scope.data = appState.data;
});
But if it must be a singleton controller you actually could use the ng-controller directive before your ng-view directive so it becomes a $rootScope like scope for all your views. After that just add empty function wrappers in your $routeProvider for the controllers.
I am trying to access $scope variable inside my controller . when I console my $scope it shows number of values but when I try to access it via $scope. it return undefined.
I have attached screen shot of $scope
Here you can see it have $id, $parent , templateUrl but when i am trying to access it via $scope.id , $scope.parent , $scope.templateUrl it return undefined .
Edited :
I am trying to access template url . actually I want to attach some params with template url so that I can get them in my backend function
here is my code :
brainframeApp.config(
['$interpolateProvider', '$locationProvider', '$httpProvider', '$routeProvider',
function($interpolateProvider, $locationProvider, $httpProvider,
$routeProvider) {
//configuring angularjs symbos to not to conflict with Django template symbols
$interpolateProvider.startSymbol('{$');
$interpolateProvider.endSymbol('$}');
//$locationProvider.html5Mode(true).hashPrefix('!');
// setup CSRF support
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
console.log("TestDavy: App");
//The route provider
$routeProvider.
when('/', {
templateUrl: '/static/engine/partials/listbrainframes.html',
controller: 'brainframeCtrl'
}).
when('/brainframe/', {
templateUrl: '/views/post.html',
controller: 'brainframeCtrlx'
}).
when('/brainframe/:id', {
templateUrl: '/views/post.html',
controller: 'brainframeCtrlx'
}).
otherwise({
redirectTo: '/'
});
}]);
my controller :
brainframeAppControllers.controller('brainframeCtrlx',
['$scope', '$routeParams', function($scope, $routeParams) {
//console.log($scope.parent);
//$scope.templateUrl = 'views/post.html?id='+$routeParams.id;
//console.log($scope);
$scope.templateUrl = 'views/post.html?id='+$routeParams.id;
//console.log($scope.templateUrl);
}]);
When I put console.log on $scope, am able to see only these properties:
["$$childTail", "$$childHead", "$$nextSibling", "$$watchers", "$$listeners", "$$listenerCount", "$id", "$$ChildScope", "$parent", "$$prevSibling"]
If you want to access the template URL inside your controller:
brainframeApp.run(function($rootScope) {
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
$rootScope.templateUrl = next.$$route.templateUrl;
});
});
Now inside your controller, inject $rootScope and get the template URL
$rootScope.templateUrl
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.
Hi I have following module, route and controller defined in one file called main.js
var mainApp = angular.module("mainApp", ["ngRoute", "ngResource", "ui"]).
config(function ($routeProvider) {
$routeProvider.
when('/addEmp', { controller: EmpCtrl, templateUrl: 'addEmp.html' }).
when('/addLoc', { controller: LocCtrl, templateUrl: 'newLocation.html' }).
otherwise({ redirectTo: '/' });
});
mainApp.factory("addEmp", ['$resource', function ($resource) {
return $resource('/api/addEmp/:id', { id: '#id' }, { update: { method: 'PUT' } });
}]);
mainApp.factory("addLoc", ['$resource', function ($resource) {
return $resource('/api/newLoc/:id', { id: '#id' }, { update: { method: 'PUT' } });
}]);
//Controllers
var EmpCtrl = function ($scope, $location, addEmp) {
//code here
};
var LocCtrl = function ($scope, $location, newLocation) {
//code here
};
What I am trying to do is organize this one file code into different files. I created script/controller folder where I want to have individual files for controller like
EmpCtrl.js and LocCtrl.js.
When I created the controller files and copied the controller code in it i get error of EmptCtrl and LocCtrl not defined.
Can you please tell me how I can set it up in different folders with appropriate path settings?
Thanks
try this
angular.module("mainApp", ["ngRoute", "ngResource", "ui"]).
config(function ($routeProvider) {
$routeProvider.
when('/addEmp', { controller: 'empCtrl', templateUrl: 'addEmp.html' }).
when('/addLoc', { controller: 'locCtrl', templateUrl: 'newLocation.html' }).
otherwise({ redirectTo: '/' });
});
//in empCtrl.js file
angular.module('mainApp').controller('empCtrl', ['$scope', '$location', 'addEmp',
function ($scope, $location, addEmp) {
//code here
}]);
// same for locCtrl
In your html make sure to include your mainApp.js file before you empCtrl and locCtrl scripts
the key is that you use string names to refer to your controller in your rout configs
{ controller: 'empCtrl' ... }
instead of
{ controller: EmpCtrl ... }
I would recommend that you use require.js to modularize your Angular project, you won't have to worry about order of script includes and it will result in a cleaner project