Using a Factory in md.dialog - angularjs

I have a google material dialog box where I interact with the user. I want to inject a factory into the dialog and use it there. Is there a way to do this?
I tried passing the factory as a local variable.
Any suggestions?
Edit ---------
Here is my controller that I am using to handle the dialogs. I output the factory to the console and the functions are all there. Not sure why calling them does nothing.
function DocumentDialogController($mdDialog, locals, chartFactory)
{
var vm = vm || this;
vm.thisItem = locals.thisItem;
vm.cancel = cancel;
vm.acceptChanges = acceptChanges;
vm.selectImage = selectImage;
function cancel(){
$mdDialog.cancel();
};
function acceptChanges(desc) {
$mdDialog.hide(desc);
};
function selectImage(imageName) {
vm.thisItem.imageObj.data.src=imageName;
};
}

Assign a controller to the dialog and inject the factory into the controller.
Do something like the below to create the dialog. Note that the string in the controller property is the name of the controller you want to use.
$mdDialog.show({
templateUrl: 'partials/example.template.html',
targetEvent: event,
controller: 'ExampleCtrl',
controllerAs: 'vm'
});
Create and inject the factory into the controller like you would with any other controller.
(function() {
'use strict';
angular
.module('example')
.controller('ExampleCtrl', ExampleCtrl);
function ExampleCtrl(ExampleFactory) {
var vm = this;
// you can now use the injected ExampleFactory
}
ExampleCtrl.$inject = ['ExampleFactory'];
})();

Related

Not able to call factory method after including factory function with $provide.factory in angular.js

app.config(['$controllerProvider','$compileProvider', '$filterProvider', '$provide',function($controllerProvider,
$compileProvider, $filterProvider, $provide) {
app.register = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
}
]);
app.controller('myCntrl', ['$scope', function($s) {
app.register.factory('customFactory',[customFactory]);
customFactory.init();
});
factory.js
function customFactory(){
var c= {};
c.init = function(){
console.log('init function');
}
return c;
}
Here I will be adding factory.js file in runtime and I now need to inject custom factory in my controller. So I have used $provide.factory method for it. But, I am not able to call init() function inside customFactory
Inside the controller that dynamically registers customFactory, the customFactory name binding is just a function. To call init() at the location you've noted, you'll need to invoke customFactory as a function.
customFactory().init();
However, if you've got another recipe elsewhere (e.g. controller) which needs to depend on customFactory, then you can access init() as you might expect.
app.controller('anotherCtrl', ['customFactory', function (customFactory) {
customFactory.init(); // OK!
}]);
When customFactory gets registered, the AngularJS dependency injector knows how to create it as a singleton and subsequently you can just access it as a value.

How to test a $uibModal instance controller?

I'm trying to test a certain controller functionality with Jasmine unit testing.
I have a function which opens a modal instance with a new controller:
function openFilterModal(data) {
var modalInstance = $uibModal.open({
controller: FilterModalController,
controllerAs: 'vm',
templateUrl: 'modal.html',
resolve: {
data: function () {
return data;
}
}
});
return modalInstance.result;
}
The controller is defined below:
FilterModalController.$inject = ['alertsModalService', '$uibModalInstance', 'data', '$scope', 'logger', '$timeout'];
function FilterModalController(alertsModalService, $uibModalInstance, data, $scope, logger, $timeout) {
// code goes here }
When I try to call 'openFilterModal', I'm unable to get the controller instance, just getting the promise from it.
I've tried to used the $controller(FilterModalController) function in Jasmine, but it couldn't find the controller.
What is the best practice in that case?
Should I add the controller definition to my module? right now it defined like anonymous controller... not sure if that's good behavior or not.
like that:
app.controller('FilterModalController', FilterModalController);
Is it ok to define 2 controllers on the same module?
Or there is another way to get test the controller?
Thanks!

Angular bootstrap modal controller scope

I'm trying to get modals woking with angular bootstrap. I can launch the modal just fine, but I'm having some scope issues dismissing the modal.
When I launch the modal, I can specify a controller that I can call functions from, which works, but it seems to be a copy of the controller without a $parent and without any controller-local variables.
I need access to the return value of $uibModal.open() in order to close the modal, so I'm trying to store it in var modalInstance, which works fine when I'm within the scope of the controller, but the copy of the controller passed into the $uibModal service doesn't have the local variable modalInstance set.
I can get around this by storing the return object in the $rootScope, but that seems like a bad idea. Am I wrong? What's the best way to get access to modalInstance from the click handler passed into the $uibModal service? Can I avoid using the $rootScope?
var app = angular.module('main', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope, $rootScope, $uibModal) {
var modalInstance;
$scope.launch = function() {
console.log('launch');
modalInstance = $uibModal.open({
template: '<div>Modal Content - <a ng-click="close()">Close</a></div>',
controller: 'MainCtrl',
});
// Wouldn't need to do this if I could access modalInstance in close handler
$rootScope.modalInstance = modalInstance;
}
$scope.close = function () {
console.log('close');
console.log(modalInstance);
// Works, but should I be using $rootScope like this?
//$rootScope.modalInstance.close();
// Doesn't work, modalInstance is undefined
modalInstance.close();
}
});
Angular instantiates a new instance of a controller whenever it is used, and it is the same for modal. So when you specify controller: 'MainCtrl' you're telling angular you want to instantiate one of those for your modal, which is rarely what you want.
Instead you should create a separate controller for the dialog, which can return values on closing using the $uibModalInstance service.
var app = angular.module('main', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope, $rootScope, $uibModal) {
var modalInstance;
$scope.launch = function() {
console.log('launch');
modalInstance = $uibModal.open({
template: '<div>Modal Content - <a ng-click="close()">Close</a></div>',
controller: 'DialogCtrl',
});
....
}
});
app.controller('DialogCtrl', function($scope, $uibModalInstance) {
$scope.theThingIWantToSave = [];
$scope.cancel = function () {
$uibModalInstance.close($scope.theThingIWantToSave);
};
});

Access variables defined in other controller

'use strict';
angular.module('sampleApplicationApp').config(function($stateProvider)
{
$stateProvider.state('abcmanagement', {
parent : 'parentmanagement',
url : '/em',
views : {
'content#' : {
templateUrl : 'scripts/app/abc.html',
controller : 'abcController'
}
}
}).state('newmodel', {
parent : 'abcmanagement',
url : '/new',
views : {
'content#' : {
templateUrl : 'scripts/app/xyz.html',
controller : 'xyzController'
}
}
})
});
angular.module('sampleApplicationApp')
.controller('abcController', function ($scope, $state, $modal) {
$scope.models = {};
// logic to load models
});
angular.module('sampleApplicationApp')
.controller('xyzController', function ($scope, $state, $modal) {
// I want to access models from above controller
});
Is there a possibility i can have access to models defined in abcController from xyzController ?
two options:
if the controllers inherit from the same parent controller, you can store the data in the parent $scope (or $rootScope, but that's bad practice);
if the controllers do not inherit from the same parent controller, use a factory to share data between controllers:
`
angular.module('sampleApplicationApp')
.factory('abcModel', function () {
var factory = {};
var model = {};
factory.setModel = function(key, value) {
model[key] = value;
}
factory.getModel = function(key) {
return model[key];
};
return factory;
});
angular.module('sampleApplicationApp')
.controller('abcController', function ($scope, $state, $modal, abcModel) {
abcModel.setModel('abc', "hello world");
});
angular.module('sampleApplicationApp')
.controller('xyzController', function ($scope, $state, $modal, abcModel) {
$scope.value = abcModel.getModel('abc');
});
You have, potentially, as many as three options:
1) If xyzController resides within abcController within your HTML then you can reference $parent.property ('property' being the name of the $scope property in the parent controller you want access to).
2) You could use $rootScope by setting any properties you want to access in multiple controllers like so, $rootScope.property. I would recommend avoiding this as it could pollute the global scope.
3) You could use an Angular service with methods for getting and setting the variables in question. Then you could simply inject this service as a dependency in each controller where you need access to these variables. Recommended approach
The best practice is that you should create an Angular service which holds the variable.
You can work around it by using the $rootScope. Don't forget to inject it in both controllers ;)
There are many ways to achieve what you are trying to do.You can create a factory or a service,you can use $rootScope(not recommended),you can use angular's broadcast, emit method to achieve this.Refer to this example http://stackoverflow.com/questions/21919962/share-data-between-angularjs-controllers

AngularJS Intercept and extend controller $scope

There is a lot of reusable functionality that I have defined in my application that EVERY controller uses with the $scope variable. Instead of me having to create a shared service each time, is there a way to extend the $scope variable so that I can have my extended code available everywhere?
Something like:
//I've tested this out and it doesn't work, but this is what I want to do.
angular.module('App',[]).config(['$scopeProvider',function($scope) {
$scope.method1 = function() { ... };
$scope.method2 = function() { ... };
}]);
Then later on:
var HomeCtrl = function($scope) {
$scope.method1();
};
Is this possible? Or do I need to create a shared service and then have the $scope extend from that for the first line of each controller?
Instead of .config try .run, this will do exactly what you want.
angular.module('App', []).run(['$rootScope', function($rootScope) {
$rootScope.foo = function() {
alert("WIN!");
};
}]);
angular.module('App').controller('HomeCtr', ['$scope', function($scope) {
$scope.foo(); #will call the alert
}]);
NOTE I have only used module.controller because I like it, var HomeCtrl = function($scope) { will have the same effect.

Resources