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.
Related
Update:
https://plnkr.co/edit/kbz5uimNZ6vKTiT9QB6a?p=preview is created for testing.
I have the following directive egFiles to handle the status of <input type="file" id="newFile" eg-files="model.files" has-file="model.hasFile" /> for file uploading.
(function () {
'use strict';
angular.module('myApp').directive('egFiles', egFiles);
function egFiles() {
var directive = {
link: link,
restrict: 'A',
scope: {
files: '=egFiles',
hasFiles: '='
}
};
return directive;
function link(scope, element, attrs) {
element.bind('change', function () {
scope.$apply(function () {
if (element[0].files) {
scope.files.length = 0; // Breakpoint not hit here
angular.forEach(element[0].files, function (f) {
scope.files.push(f);
});
scope.hasFiles = true;
}
});
});
if (element[0].form) {
angular.element(element[0].form)
.bind('reset', function () {
scope.$apply(function () {
scope.files.length = 0;
scope.hasFiles = false;
});
});
}
}
}
})();
The following the Anguar 1.5 component to consume the directive.
(function (undefined) {
'use strict';
angular.module('myApp')
.component('doc', {
template: '...
<input type="file" id="newFile" eg-files="model.files" has-file="model.hasFile" />
....',
bindings: {
id: '<',
"$router": '<'
},
controllerAs: 'model',
controller: [controller]
});
function controller() {
var model = this;
model.$routerOnActivate = function (next, previous) {
model.id = next.params.id;
}
model.hasFile = false;
model.uploading = false;
}
})();
I set the break point in the function bound to change in directive egFiles. However the break point is never hit when I select a file by click the button?
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 !
});
}
}
}]);
How can I call function loadTable from another controller?
app.controller('tableCtrl', ['$scope', function (scope) {
scope.loadTable = function() {
//some code
};
});
app.controller('secondCtrl', ['$scope', function (scope) {
scope.buttonClick = function() {
//call loadTable from tableCtrl
};
});
Try $emit-$on(publish-subscribe) mechanism.
app.controller('tableCtrl', ['$scope', function (scope) {
scope.loadTable = function() {
//some code
};
$rootScope.$on('load-table', function (event, arg1, arg2) {
// now trigger the method.
scope.loadTable();
});
});
app.controller('secondCtrl', ['$scope', function (scope) {
scope.buttonClick = function() {
//call loadTable from tableCtrl
//emit the event
$rootScope.$emit('load-table', 'arg1', 'arg2');
};
});
You should perhaps use a service such as
app.factory('tableService', [function () {
return {
loadTable : function() {
//some code
}
};
});
app.controller('tableCtrl', ['$scope', 'tableService', function (scope, tableService) {
});
app.controller('secondCtrl', ['$scope', 'tableService', function (scope, tableService) {
scope.buttonClick = function() {
tableService.loadTable();
};
});
Your tableCtrl would then need to save any data using another function on the service.
I am trying to write a unit test for the toggleDetails function defined inside the following AngularJS directive:
angular.module('hadoopApp.cluster.cluster-directive', [])
.directive('cluster', [function() {
return {
templateUrl:'components/cluster/cluster.html',
restrict: 'E',
replace: true,
scope: {
clusterData: '=',
showDetails: '='
},
link: function(scope, element, attrs) {
scope.toggleDetails = function() {
console.log('Test');
scope.showDetails = !scope.showDetails;
};
},
// Default options
compile: function(tElement, tAttrs){
if (!tAttrs.showDetails) { tAttrs.showDetails = 'false'; }
}
};
}]);
And this is the unit test:
'use strict';
describe('hadoopApp.cluster module', function() {
// Given
beforeEach(module('hadoopApp.cluster.cluster-directive'));
var compile, mockBackend, rootScope;
beforeEach(inject(function($compile, $httpBackend, $rootScope) {
compile = $compile;
mockBackend = $httpBackend;
rootScope = $rootScope;
}));
var dummyCluster;
beforeEach(function() {
dummyCluster = {
id:"189",
name:"hadoop-189",
exitStatus:0
};
mockBackend.expectGET('components/cluster/cluster.html').respond(
'<div><div ng-bind="clusterData.name"></div></div>');
});
it('should toggle cluster details info', function() {
var scope = rootScope.$new();
scope.clusterData = dummyCluster;
// When
var element = compile('<cluster' +
' cluster-data="clusterData" />')(scope);
scope.$digest();
mockBackend.flush();
// Then
var compiledElementScope = element.isolateScope();
expect(compiledElementScope.showDetails).toEqual(false);
// When
console.log(compiledElementScope);
compiledElementScope.toggleDetails();
// Then
expect(compiledElementScope.showDetails).toEqual(true);
});
afterEach(function() {
mockBackend.verifyNoOutstandingExpectation();
mockBackend.verifyNoOutstandingRequest();
});
});
The test fails when calling compiledElementScope.toggleDetails() because the toggleDetails function is undefined:
TypeError: undefined is not a function
Printing the content of the isolated scope inside compiledElementScope I can see that in fact the function is not included in the object.
So, it looks like the toggleDetails function is not included in the isolated scope but I don't know why.
If you use the compile function within a directive, the link function is ignored. You should return the function within the compile method:
compile: function (tElement, tAttrs) {
if (!tAttrs.showDetails) {
tAttrs.showDetails = 'false';
}
return {
post: function (scope, element, attrs) {
console.log('Test');
scope.toggleDetails = function () {
console.log('Test');
scope.showDetails = !scope.showDetails;
};
}
};
}
Also, in order to make the test work, you should add:
scope.showDetails = false;
And the binding to the directive (because you require two values):
var element = compile('<cluster' +
' cluster-data="clusterData" show-details="showDetails" />')(scope);
Jsfiddle: http://jsfiddle.net/phu7sboz/
I'd like to call "myFunc()" inside my angular directive, how might I do this?
myApp.directive("test", function () {
return {
restrict: 'A',
template: "<div class='box'></div>",
myFunc: function() {
console.log('myFunc');
},
link: function ($scope, element, attrs) {
element.bind('click', function () {
myFunc(); //<------------- doesn't work
});
}
} // of return
});
You can't define the function as a property of your return value in your call to directive. It either needs to be defined before your return:
myApp.directive('test', function() {
var myFunc = function() {
console.log('myFunc');
};
return {
restrict: 'A',
template: '<div class="box"></div>',
link: function($scope, element, attrs) {
element.bind('click', myFunc);
}
};
};
Or the same way inside of your link function.
Just to play around :)
var app = angular.module('myApp', []);
app.controller('MainController',function() {
});
app.directive('one', function() {
return angular.extend({}, app.directive, {myfunct:function(){
alert('hello');
}});
});
app.directive('two', function(oneDirective) {
return {
link:function($scope,$element){
console.log(oneDirective[0].myfunct)
$element.on('click',oneDirective[0].myfunct);
}
};
});
or use the method binding "&":
app.directive('myDir', function() {
return {
scope: {
callback: "&"
},
link:function($scope,$element){
element.bind('click', function () {
$scope.evalAsync(function() {
$scope.callback({param1: value, param2: value2});
})
});
}
};
});
Usage:
<my-dir callback="myControllerMethod(param1, param2)"></my-dir>