AngularJS : Call controller function from outside with vm - javascript

Here I have :
var app = angular.module('app');
app.controller("myController", function () {
var vm = this;
vm.myFunction = function() { alert('foo'); };
});
app.animation('.animate', ["$timeout", function($timeout) {
var vm = this;
return {
addClass: function(element, className, doneFn) {
$timeout(function() {
console.log('this is displayed');
vm.myFunction(); // Doesn't work !
});
}
}
}]);
When I add a class in the template, addClass gets fired. However, vm.myFunction() doesn't, because it does not exist.
How do we do this in angular ?

Some different from yours but I thought this can help you...
in HTML
<div id="outer" ng-controller="myController"></div>
in JS
var app = angular.module('app');
app.controller('myController', function ($scope) {
$scope.myFunction = function() { alert('foo'); };
});
var scope = angular.element($("#outer")).scope();
scope.myFunction();

Modify your code as the following:
var app = angular.module('app');
app.controller('myController', function ($scope) {
var vm = this;
vm.myFunction = function() { alert('foo'); };
$scope = vm;
});
app.animation('.animate', ["$timeout", 'myController', function($timeout, myController) {
var vm = myController;
return {
addClass: function(element, className, doneFn) {
$timeout(function() {
console.log('this is displayed');
vm.myFunction(); // Doesn't work !
});
}
}
}]);

Related

Testing Angular modalInstance within the same controller

I'm using the ui-bootstrap modal window and I'm trying to test a method that fires that modal window. My controller:
app.controller('AddProductController', ['$scope', 'ProductsService', '$uibModal', function ($scope, ProductsService, $uibModal) {
$scope.product = {};
$scope.searchCategories = function () {
ProductsService.getRootCategories().then(function (data) {
$scope.categories = data.data;
});
$scope.modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: 'categoryContent.html',
controller: 'AddProductController',
scope: $scope
});
$scope.modalInstance.result.then(function (category) {
$scope.searchCategory = null;
$scope.product.category = category;
}, function () {
});
};
$scope.ok = function(){
$scope.modalInstance.close($scope.product.category);
};
$scope.cancel = function(){
$scope.modalInstance.dismiss();
}]);
And my test:
describe("Products Controller", function () {
beforeEach(function () {
module('productsController');
});
beforeEach(function () {
var ProductsService, createController, scope, rootScope,
module(function ($provide) {
$provide.value('ProductsService', {
getRootCategories: function () {
return {
then: function (callback) {
return callback({data: {name: 'category1'}});
}
};
},
});
$provide.value('$uibModal', {
open : function(){
return {
then: function (callback) {
return callback({data: {name: 'category1'}});
}
};
}
});
return null;
});
});
describe('AddProductController', function () {
beforeEach(function () {
inject(function ($controller, _$rootScope_, _ProductsService_) {
rootScope = _$rootScope_;
scope = _$rootScope_.$new();
ProductsService = _ProductsService_;
createController = function () {
return $controller("AddProductController", {
$scope: scope,
});
};
});
});
it('calling searchCategories should make $scope.categories to be defined', function () {
createController();
expect(scope.categories).not.toBeDefined();
scope.searchCategories();
expect(scope.categories).toBeDefined();
});
});
});
All my tests pass,except this one, where I get TypeError: $scope.modalInstance.result is undefined.
Any clues?
It seems you're not defining result in your mock modal. Try something like this:
$provide.value('$uibModal', {
open: function () {
return {
result : {
then: function (callback) {
return callback({ data: { name: 'category1' } });
}
}
};
}
});

AngularJS/Ionic/SinonChai - How to mock up the $ionicModal.fromTemplateUrl function

I am having trouble in my test for an ionic modal controller. The problem (or at least the problem I'm focusing on) is mocking up the $ionicModal.fromTemplateUrl function. According to ionic documentation, it's supposed to return a promise that resolves into an instance of the modal.
Here is my factory:
(function() {
'use strict';
angular.module('penta.app.main').factory('addEquipment', AddEquipment);
function AddEquipment($rootScope, $ionicModal) {
return {
openModal: function() {
var scope = $rootScope.$new(true);
scope.controller = new AddEquipmentController(scope, $ionicModal);
}
};
function AddEquipmentController(scope, $ionicModal) {
var controller = this;
$ionicModal.fromTemplateUrl('app/tracking/activityLog/addItems/equipment/addEquipment.html', {
scope: scope,
animation: 'slide-in-up'
}).then(function(modal) {
controller.modal = modal;
controller.openModal();
});
controller.openModal = function() {
controller.modal.show();
};
controller.closeModal = function() {
controller.modal.hide();
};
return controller;
}
}
})();
And here is my test:
(function() {
'use strict';
describe('AddEquipment', function() {
var controllerConstructor;
var addEquipment;
var mock;
var mockIonicModal;
var mockModal;
var scope;
var dfd;
beforeEach(module('penta.app.main'));
beforeEach(module('unitTest'));
beforeEach(module('app/tracking/activityLog/addItems/equipment/addEquipment.html'));
beforeEach(function() {
mockModal = sinon.stub({
show: function() {
},
hide: function() {
}
});
mockIonicModal = sinon.stub({
fromTemplateUrl: function() {
},
then: function() {
}
});
mockIonicModal.fromTemplateUrl.returns(mockModal);
});
beforeEach(function() {
module(function($provide) {
$provide.value('$ionicModal', mockIonicModal);
});
});
beforeEach(inject(function($rootScope, $controller, $q, ptiMock) {
controllerConstructor = $controller;
dfd = $q.defer();
scope = $rootScope.$new();
mock = ptiMock;
mockModal.$promise = dfd.promise;
}));
beforeEach(inject(function(_addEquipment_) {
addEquipment = _addEquipment_;
}));
it('exists', function() {
expect(addEquipment).to.exist;
});
describe('open', function() {
it.only('opens the modal', function() {
addEquipment.openModal();
dfd.resolve(mockModal);
scope.$digest();
expect(mockIonicModal.show.calledOnce).to.be.true;
});
});
function getController() {
return mockIonicModal.fromTemplateUrl.lastCall.args[0].scope.controller;
}
});
})();
I'm also unsure if my getController function will properly return the controller. This is my first time working with $ionicModal, so any pointers are appreciated. Thanks.
FIXED:
I didn't have the dfd set up properly. Also I had the show set as a function of mockIonicPopup when it is a function of mockModal.
(function() {
'use strict';
describe('AddEquipment', function() {
var controllerConstructor;
var addEquipment;
var mock;
var mockIonicModal;
var mockModal;
var scope;
var dfd;
beforeEach(module('penta.app.main'));
beforeEach(module('unitTest'));
beforeEach(module('app/tracking/activityLog/addItems/equipment/addEquipment.html'));
beforeEach(function() {
mockModal = sinon.stub({
show: function() {
},
hide: function() {
}
});
mockIonicModal = sinon.stub({
fromTemplateUrl: function() {
},
then: function() {
}
});
});
beforeEach(function() {
module(function($provide) {
$provide.value('$ionicModal', mockIonicModal);
});
});
beforeEach(inject(function($rootScope, $controller, $q, ptiMock) {
controllerConstructor = $controller;
dfd = $q.defer();
scope = $rootScope.$new();
mock = ptiMock;
mockIonicModal.fromTemplateUrl.returns(dfd.promise);
}));
beforeEach(inject(function(_addEquipment_) {
addEquipment = _addEquipment_;
}));
it('exists', function() {
expect(addEquipment).to.exist;
});
describe('openModal', function() {
it.only('opens the modal', function() {
addEquipment.openModal();
dfd.resolve(mockModal);
scope.$digest();
expect(mockModal.show.calledOnce).to.be.true;
});
});
function getController() {
return mockIonicModal.fromTemplateUrl.lastCall.args[0].scope.controller;
}
});
})();

angular controller can't see function declared in directive

Here is the html:
<div class="col-lg-8" ng-controller="usersCtrl">
<scrollable height="180" ts-attach-spinner class="list-group">
</scrollable>
</div>
Here is the directive:
(function() {
'use strict';
angular
.module('angle')
.directive('tsAttachSpinner', tsAttachSpinner);
tsAttachSpinner.$inject = ['$window'];
function tsAttachSpinner($window) {
var directive = {
link: link,
restrict: 'A'
};
return directive;
function link(scope, element, attrs) {
function spinnerOff() {
element.className = element.className + " whirl standard";
}
function spinnerOn() {
element.className = element.className.replace(" whirl standard", "");
}
scope.spin = function (promises) {
return $q.all(promises).then(function (eventArgs) {
spinnerOff();
});
}
}
}
})();
Here is the controller:
(function () {
'use strict';
angular
.module('angle')
.controller('usersCtrl', usersCtrl);
usersCtrl.$inject = ['$scope', 'usersSvc'];
function usersCtrl($scope, usersSvc) {
$scope.title = 'Users';
activate();
function activate() {
var promises = [getUsers()];
$scope.spin(promises);
}
function getUsers() {
return usersSvc.getUsers().then(function (data) {
return $scope.users = data;
});
}
}
})();
As you can see, I declare the spin function and attach it to the scope in the ts-attach-spinner directive. However, I am getting "undefined is not a function", when I call $scope.spin in the controller.
All advice appreciated, thanks in advance.

How to communicate controller with each other in AngularJS?

I'm writing a controller. This controller has to communicate with an other controller. But I don't know is it posible?
HTML:
<div data-ng-app="TestApp">
<div data-ng-controller="menuCtrl">
<ul>
<li> <a data-ng-click="Click()">
MenĂ¼1</a>
</li>
</ul>
</div>
<div data-ng-controller="pageCtrl">
<hr/>
<button data-ng-click="getText()">GetText</button>
<br/>
<strong data-ng-model="boldText"> {{boldText}}</strong>
</div>
JS:
var app = angular.module('TestApp', []);
app.controller('menuCtrl', function ($rootScope, $scope) {
$scope.Click = function () {
//???
};
})
.controller('pageCtrl', function ($rootScope, $scope) {
$scope.getText = function () {
$scope.boldText = 'tst';
};
});
I repaired sample on JSfiddle:sample
You can easily achieve that with broadcasting:
var app = angular.module('TestApp', []);
app.controller('menuCtrl', function ($rootScope, $scope) {
$scope.Click = function () {
$scope.$broadcast('MyClickEvent', {
someProp: 'Clicking data!' // send whatever you want
});
};
})
.controller('pageCtrl', function ($rootScope, $scope) {
$scope.getText = function () {
$scope.boldText = 'tst';
};
$scope.$on('MyClickEvent', function (event, data) {
console.log(data); // 'Data to send'
});
});
Using the events broadcast, we can pass the value form one controller to another
app.controller('menuCtrl', function ($rootScope, $scope) {
$scope.Click = function () {
var valueToPass = "value";
$rootScope.$broadcast('eventMenuCtrl', valueToPass);
};
})
.controller('pageCtrl', function ($rootScope, $scope) {
$scope.getText = function () {
$scope.boldText = 'tst';
};
$scope.$on('eventMenuCtrl', function(event, value) {
$scope.boldText = value;
})
});
http://jsfiddle.net/q2yn9jqv/4/

Call a controller function from Karma and Jasmine testing

This is my angular controller :-
angular.module('authoring-controllers', []).
controller('NavCtrl', function($scope, $location, BasketNavigationService) {
$scope.test= function() {
$scope.testVar = BasketNavigationService.showBasketList();
};
});
TEST class
describe('NavCtrl', function() {
var scope, $location, createController;
beforeEach(inject(function ($rootScope, $controller, _$location_) {
$location = _$location_;
scope = $rootScope.$new();
createController = function() {
return $controller('NavCtrl', {
'$scope': scope
});
};
}));
it('should create $scope.testVar when calling test',
function() {
expect(scope.testVar).toBeUndefined();
scope.test();
expect(scope.testVar).toBeDefined();
});
});
Getting an error when i run that test case :- scope.test() is undefined..
If i removed BasketNavigationService functionality from controller then it is working..
Please help me to solve that karma test case.
here is the working demo , hope it helps.
problem was with injecting the dependencies.
//--- CODE --------------------------
(function(angular) {
// Create module
var myApp = angular.module('myApp', []);
// Controller which counts changes to its "name" member
myApp.controller('MyCtrl', ['$scope', 'BasketNavigationService',
function($scope, BasketNavigationService) {
$scope.test = function() {
$scope.testVar = BasketNavigationService.showBasketList();;
};
}
]);
})(angular);
// ---SPECS-------------------------
describe('myApp', function() {
var scope,
controller;
beforeEach(function() {
module('myApp');
});
describe('MyCtrl', function() {
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller('MyCtrl', {
'$scope': scope,
'BasketNavigationService': {
showBasketList: function() {
return null;
}
}
});
}));
it('should create $scope.testVar when calling test',
function() {
expect(scope.testVar).toBeUndefined();
scope.test();
// scope.$digest();
expect(scope.testVar).toBeDefined();
});
});
});
// --- Runner -------------------------
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
<script src="http://jasmine.github.io/1.3/lib/jasmine.js"></script>
<script src="http://jasmine.github.io/1.3/lib/jasmine-html.js"></script>
<script src="https://code.angularjs.org/1.2.9/angular.js"></script>
<script src="https://code.angularjs.org/1.2.9/angular-mocks.js"></script>
<link href="http://jasmine.github.io/1.3/lib/jasmine.css" rel="stylesheet" />
fiddle : http://jsfiddle.net/invincibleJai/pf1deoom/1/
Please change your createController setup to:
createController = function() {
return $controller('NavCtrl', {
'$scope': scope,
'$location':$location,
'BasketNavigationService':{showBasketList: function(){return 'test'} }
});
};
You are not injecting all the dependencies.
I have injected dummy BasketNavigationService, you can inject the real one.
Have you tried running createController();? I don't think your NavCtrl controller gets mocked.

Categories