How to load/inject a service in the main app controller? - javascript

I am trying to implements a modal from this answer but I fail to use the service in the app controller. The question is simple: How can I use the modalService via injection in the emaApp main controller?
modal.js
angular.module('emaApp', []).service('modalService', [ '$modal',
// NB: For Angular-bootstrap 0.14.0 or later, use $uibModal above instead of $modal
function($modal) {
var modalDefaults = {
backdrop : true,
keyboard : true,
modalFade : true,
templateUrl : '/app/partials/modal.html'
};
var modalOptions = {
closeButtonText : 'Close',
actionButtonText : 'OK',
headerText : 'Proceed?',
bodyText : 'Perform this action?'
};
this.showModal = function(customModalDefaults, customModalOptions) {
if (!customModalDefaults)
customModalDefaults = {};
customModalDefaults.backdrop = 'static';
return this.show(customModalDefaults, customModalOptions);
};
this.show = function(customModalDefaults, customModalOptions) {
//Create temp objects to work with since we're in a singleton service
var tempModalDefaults = {};
var tempModalOptions = {};
//Map angular-ui modal custom defaults to modal defaults defined in service
angular.extend(tempModalDefaults, modalDefaults, customModalDefaults);
//Map modal.html $scope custom properties to defaults defined in service
angular.extend(tempModalOptions, modalOptions, customModalOptions);
if (!tempModalDefaults.controller) {
tempModalDefaults.controller = function($scope, $modalInstance) {
$scope.modalOptions = tempModalOptions;
$scope.modalOptions.ok = function(result) {
$modalInstance.close(result);
};
$scope.modalOptions.close = function(result) {
$modalInstance.dismiss('cancel');
};
};
}
return $modal.open(tempModalDefaults).result;
};
} ]);
index.js
var app = angular.module('emaApp', []);
app.controller('mainCtrl',['$scope', '$http', 'modalService', function($scope, $http, modalService) {
$scope.deleteModel = function(modelId) {
var modalOptions = {
closeButtonText : 'Cancel',
actionButtonText : 'Delete Customer',
headerText : 'Delete ' + modelId + '?',
bodyText : 'Are you sure you want to delete this model?'
};
modalModule.showModal({}, modalOptions).then(function(result) {
//your-custom-logic
alert("muaha")
});
}
}]);

You are defining module emaApp multiple times. Hence overwriting the existing module, You need to retrieve module in file which is loaded later i.e. index.js, notice removed []
var app = angular.module('emaApp');
instead of
var app = angular.module('emaApp', []);

You already injected the service into your controller. You should use modalService instead of -possibly- undefined modalModule in your controller.

Related

$uibModalProvider <- $uibModal <- StatusModalService giving error

Trying to built a modal with angularjs and ui-bootstrap:
Version
Angularjs and its component is 1.5.3
ui-bootstrap-tpls-1.3.3.js.
In main app file I have included 'ui.bootstrap' as
var App = angular.module('aotaApp', ['ui.router','ui.bootstrap','checklist-model','ngSanitize'])
.controller("myController", function($scope,$state, $http)
In StatusService I am using this as
App.service("StatusModalService", ["$uibModal",
function ($uibModal) {
var modalDefaults = {
backdrop: true,
keyboard: true,
modalFade: true,
templateUrl: 'resources/template/modal/confirmationModal.html'
};
var modalOptions = {
closeButtonText: 'Close',
actionButtonText: 'OK',
headerText: 'Proceed?',
bodyText: 'Perform this action?'
};
this.showModal = function (customModalDefaults, customModalOptions) {
if (!customModalDefaults) customModalDefaults = {};
customModalDefaults.backdrop = 'static';
return this.show(customModalDefaults, customModalOptions);
};
this.show = function (customModalDefaults, customModalOptions) {
//Create temp objects to work with since we're in a singleton service
var tempModalDefaults = {};
var tempModalOptions = {};
//Map angular-ui modal custom defaults to modal defaults defined in service
angular.extend(tempModalDefaults, modalDefaults, customModalDefaults);
//Map modal.html $scope custom properties to defaults defined in service
angular.extend(tempModalOptions, modalOptions, customModalOptions);
if (!tempModalDefaults.controller) {
tempModalDefaults.controller = function ($scope, $uibModalInstance) {
$scope.modalOptions = tempModalOptions;
$scope.modalOptions.ok = function (result) {
$uibModalInstance.close(result);
};
$scope.modalOptions.close = function (result) {
$uibModalInstance.dismiss('cancel');
};
}
}
return $uibModal.open(tempModalDefaults).result;
};
}]);
But I am getting error
angular-1.5.3.js:13424 Error: [$injector:unpr] Unknown provider:
$uibModalProvider <- $uibModal <- StatusModalService
I am new to angular and mainly found to add ui.bootstrap in app. but it's not giving any help.
Please guide me.
It seems like a version issue, Need to upgrade your ui-bootstrap
https://github.com/compact/angular-bootstrap-lightbox/issues/42
Install latest version of angular-bootstrap
npm install angular-bootstrap or bower install angular-bootstrap
This could also be due to a renaming of $uibModal. If you have this error, try using $modal instead.

Angular Directive update view from template url

I have started learning angularjs recently and I am doing some stuff. I tried to use this actice example, especially 3 example. I tried to read from tempate files by their url but I couldn't. I got bellow code (here only peace of code which I changed):
var app = angular.module('app', []);
app.value('MultiViewPaths',
{'/' : {
content : {
templateUrl : './templates/_header.html'
},
secondaryContent : {
templateUrl : './templates/_secondaryContent.html',
controller : 'ListUsersCtrl'
}
},
'/cats' : {
content: {
templateUrl : 'templates/_headerCats.html',
controller : 'ListCatsCtrl'
},
secondaryContent : {
templateUrl : 'templates/_secondaryContentCats.html',
controller : 'CatOfTheMinuteCtrl'
}
}
});
app.directive("ngMultiView", ['$rootScope', '$compile', '$controller', '$location', 'MultiViewPaths','$templateCache', function($rootScope, $compile, $controller, $location, MultiViewPaths, $templateCache){
var getTemplate = function(templateUrl) {
console.log(templateUrl)
var template = $templateCache.get(templateUrl);
console.log(template)
return template
}
return {
terminal: true,
priority: 400,
transclude: 'element',
compile : function(element, attr, linker){
return function(scope, $element, attr) {
var currentElement,
panel = attr.ngMultiView;
$rootScope.$on('$locationChangeSuccess', update);
update();
// update view
function update(evt, newUrl, oldUrl){
if(!newUrl){ return }
var url = newUrl.match(/#(\/.*)/),
match, template, controller;
match = url ? MultiViewPaths[url[1]] : MultiViewPaths['/'];
template = getTemplate(match[panel].templateUrl);
console.log(template)
controller = match[panel].controller;
if(template){
var newScope = scope.$new(),
locals = {},
newController = controller;
linker(newScope, function(clone){
clone.html(template);
$element.parent().append(clone);
if(currentElement){
currentElement.remove();
}
var link = $compile(clone.contents());
currentElement = clone;
if (newController) {
locals.$scope = newScope;
var controller = $controller(newController, locals);
clone.data('$ngControllerController', newController);
clone.children().data('$ngControllerController', newController);
}
link(newScope);
newScope.$emit('$viewContentLoaded');
});
}else{
//cleanup last view
}
}
}
}
}
}]);
Other thing the same with example. I could not read templates inner html. Can anyone help me ?
I would recommend using uiRouter rather than ngRouter. With uiRouter you do not need to create a directive to handle changing the view for different URL parameters.
They give an example of how to do this using the $stateProvider here http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$stateProvider
templateUrl: function(params) {
return myTemplates[params.pageId]; }

Angular controller testing with many dependencies

I am learning AngularJS by building a small Real estate app. As i am new to AngularJS, i have very little knowledge about controller testing with many dependencies. I google about that but found very few information. Any help would be appreciated.
The following test is failing:
it('should create "proterties" model with 1 property fetched from xhr', function() {
$httpBackend.flush();
scope.properties = scope.getResultsPage(1);
expect(scope.properties).toEqual(propertiesData());
});
ControllersSpecs.js:
'use strict';
/* jasmine specs for controllers go here */
describe('Realty controllers', function() {
beforeEach(module('realtyApp'));
beforeEach(module('angularUtils.directives.dirPagination'));
beforeEach(module('realtyFilters'));
beforeEach(module('realtyServices'));
describe('PropertyListCtrl', function(){
var scope, ctrl, $httpBackend;
function propertiesData() {
return {
"total": 1,
"data":[{
"id": "26",
"property_type": "apartment",
"amount": "600",
"address": "26 Marsh St, Wolli Creek",
}]
}
};
// Learn more about dependency injection for testing
// https://docs.angularjs.org/tutorial/step_05
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('/api/properties?page=1').
respond(propertiesData());
scope = $rootScope.$new();
ctrl = $controller('PropertyListCtrl', {$scope: scope});
}));
it('should create "proterties" model with 1 property fetched from xhr', function() {
$httpBackend.flush();
scope.properties = scope.getResultsPage(1);
// scope.properties = propertiesData();
expect(scope.properties).toEqual(propertiesData());
});
});
});
Main app module:
'use strict';
/* App Module */
var realtyApp = angular.module('realtyApp', [
'ngRoute',
'angularUtils.directives.dirPagination',
'realtyControllers',
'realtyFilters',
'realtyServices'
]);
Property List controller
'use strict';
/* Controllers */
var realtyControllers = angular.module('realtyControllers', []);
realtyControllers.controller('PropertyListCtrl', ['$scope', 'Property', 'propertyImage', 'propertyData',
function($scope, Property, propertyImage, propertyData) {
$scope.beds = propertyData.beds();
$scope.bathrooms = propertyData.bathrooms();
$scope.garageSpaces = propertyData.garageSpaces();
// Paginate properties
$scope.totalProperties = 0;
$scope.propertiesPerPage = 10; // this should match however many results your API puts on one page
$scope.pagination = {
current: 1
};
$scope.getResultsPage = function getResultsPage(pageNumber) {
// The following will generate :
// http://realty.dev/api/properties?page=1
Property.get({page:pageNumber}, function(result) {
$scope.properties = result.data;
$scope.totalProperties = result.total;
});
}
$scope.getResultsPage(1);
$scope.pageChanged = function(newPage) {
$scope.getResultsPage(newPage);
};
$scope.isCarSpaceAvailable = function(carSpace) {
if (carSpace != 0) {
return true;
}
return false;
}
$scope.getPropertyImage = function(photo) {
return propertyImage.jpg(photo.name);
}
$scope.clearFilters = function() {
$scope.filter = {};
}
}]);
Edit 1:
I am getting the following error:
When you do
scope.properties = scope.getResultsPage(1);
you affect properties to what is return from getResultsPage and nothing is return from that function.
Can you try (I think flush should be call after the method) :
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
$httpBackend = _$httpBackend_;
$httpBackend.whenGET('/api/properties?page=1').
respond(propertiesData());
/**** your code *****/
}));
it('should create "proterties" model with 1 property fetched from xhr', function() {
$httpBackend.expectGET('/api/properties?page=1');
scope.getResultsPage(1);
$httpBackend.flush();
// scope.properties = propertiesData();
expect(scope.properties).toEqual(propertiesData());
});

How can I pass down a value in the $scope to an inner controller in AngularJS?

In my angular app.js that's the main controller in my index.html I want to have a function like this:
$scope.login = function (user) {
$scope.authenticating = true;
var config = {
method: 'POST',
url: '/api/Account/Login',
data: {
'userName': user.loginUserName,
'password': user.loginPassword,
'rememberMe': user.loginRememberMe
}
};
$http(config)
.success(function (data) {
authentication.isAuthenticated = true;
authentication.userName = user.loginUserName;
localStorage.isAuthenticated = 'yes';
$scope.template = $scope.templates[1];
$state.transitionTo('home');
})
};
In my controllers that are for templates inside index.html I want to be able to get access to the userName. Can someone tell me how I can do this? Initially I tried setting $scope.user = {} in the app.js and then setting $scope.user.userName but when I open another template and its controller that's inside app.js the $scope.user does not seem to be visible.
You could use a service to share data between controllers
app.service('userService', function() {
var user = {};
setUserName = function(name) {
user.name = name;
};
getUser = function(){
return user;
};
});
Controller that sets data
app.controller('FooController', ['$scope', 'userService',
function ($scope, userService) {
$scope.login = function (user) {
$scope.authenticating = true;
var config = {
method: 'POST',
url: '/api/Account/Login',
data: {
'userName': user.loginUserName,
'password': user.loginPassword,
'rememberMe': user.loginRememberMe
}
};
$http(config)
.success(function (data) {
authentication.isAuthenticated = true;
userService.setUserName(user.loginUserName);
localStorage.isAuthenticated = 'yes';
$scope.template = $scope.templates[1];
$state.transitionTo('home');
})
};
}
]);
Other Controller, that retrieves data
app.controller('BarController', ['$scope', 'userService', function($scope, userService) {
var username = userService.getUser().name
});
Since your retrieval is async, you might need to add some event/callback mechanism to your user service, so the controllers get notified when the name is set / changes.
All child controllers inherit $scope variables from parents
<div ng-controller="c1">
<div ng-controller="c2"></div>
</div>
youApp.controller('c1', ['$scope', function($scope){
$scope.blabla = 1;
}]);
youApp.controller('c2', ['$scope', function($scope){
// $scope.blabla is also 1 here because c2 is a child of c1
}]);
You can store anydata in built-in $rootScope service. Services are singleton in Angular
yourApp.run(['$rootScope', functin($rootScope){
$rootScope.foo = 'bar';
// you can inject $rootScope in any controller you want and use $rootScope.foo
}]);
As #Robin suggest, I also recommend to write your own service for authorization

How to $inject dynamically dependence in a controller

I'm still a debutant on Angularjs.
I want to inject dynamically a dependency of a service (that I created) in my controller.
But when I code a service with dependencies, I got this error :
Error: Unknown provider: $windowProvider <- $window <- base64
This is the code of the controller.
var base64 = angular.injector(['servicesModule']).get('base64');
console.log("base64", base64.encode("my text will be encoded"));
This code works:
var servicesModule = angular.module('servicesModule', []);
servicesModule.factory('base64', function() {
return {
name: 'base64',
readonly: false,
encode: function(input) {
return window.btoa(input);
},
decode: function(input) {
return window.atob(input);
}
};
});
This code doesn't work :
var extModule = angular.module('ext', []);
extModule.factory('base64', ['$window', function($window) {
return {
name: 'base64',
readonly: false,
encode: function(input) {
return $window.btoa(input);
},
decode: function(input) {
return $window.atob(input);
}
};
}]);
Another problem is when the service is in the same module as the controller.
If the module has dependencies, I doesn't work (I have $routeProvider dependence in my module config) :
Error: Unknown provider: $routeProvider from mainModule
var mainModule = angular.module('main', [],
function($routeProvider, $locationProvider) {
//Some routing code
}
);
JS Fiddles
Same module with dependencies(controller + service) : http://jsfiddle.net/yrezgui/YedT2/
Different module with dependencies : http://jsfiddle.net/yrezgui/YedT2/4/
Different module without dependencies : http://jsfiddle.net/yrezgui/YedT2/5/
Don't call angular.injector() -- this creates a new injector. Instead, inject the already-created $injector into your controller and use it:
So instead of:
var algoController = function($scope) {
$scope.base64 = angular.injector(['main']).get('base64');
};
Do this:
var algoController = function($scope, $injector) {
$scope.base64 = $injector.get('base64');
};
But most of the time you should inject your service directly, rather than dynamically, like so:
var algoController = function($scope, base64) {
$scope.base64 = base64;
};
See also AngularJS dynamically inject scope or controller

Categories