Angular directive controller: Argument is not a function, got undefined - javascript

I have created a directive inside my controller, which i want to include another controller to the directive. The error i get back is Error: [ng:areq] Argument 'js/controllers/testview/DocumentController.js' is not a function, got undefined
TestviewController
app.controller('TestviewController', ['$http', '$scope', '$sessionStorage', '$state', '$log', 'Session', 'api', function ($http, $scope, $sessionStorage, $state, $log, Session, api) {
var module_id = $state.params.id;
$http.get(api.getUrl('componentsByModule', module_id))
.success(function (response) {
$scope.components = response;
});
}]);
app.directive('viewDoc', function () {
return {
templateUrl: "tpl/directives/testview/document.html",
controller: "js/controllers/testview/DocumentController.js",
resolve: { components: function() { return $scope.components }}
};
});
DocumentController
app.controller('DocumentController', ['$http', '$scope', '$sessionStorage', '$state', '$log', 'Session', 'api', 'components', function ($http, $scope, $sessionStorage, $state, $log, Session, api, components) {
$scope.components = components;
}]);
I'm pretty new with directices, but does anyone have any idea what I'm doing wrong?

Inside the directive definition object, the controller property expects a string with the function name, or the function itself (not the path to script file).
app.directive('viewDoc', function () {
return {
...
controller: "DocumentController",
};
});

You want to call the controller by name, not by file name:
controller: "js/controllers/testview/DocumentController.js"
should be
controller: "DocumentController"

There is no option to put controller by its URL in the directive definition. However if you define your controller in DOM template you could use controller: 'myController as myCtrl' in directive definition

are you sure you need a directive controller? i think what you are trying to achieve is link function.
you can use directive link functions like controllers.
.directive('myDialog', function() {
return {
restrict: 'E',
transclude: true,
scope: {},
templateUrl: 'my-dialog.html',
link: function (scope, element) {
scope.name = 'Jeff';
}
};
});
take a look at angular docs
https://docs.angularjs.org/guide/directive

Related

Trouble passing angular resolve values into controller

How do I pass the resolve validToken value to my controller?
Config:
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/recover/:token', {
templateUrl: 'recover.html',
controller: 'recoverCtrl',
resolve: {
validToken : function(){
return "INVALID TOKEN"
}
}
});
}])
Controller:
.controller('recoverCtrl', ['$location','$scope','$http', '$routeParams', '$rootScope',
function($location,$scope,$http,$routeParams,$rootScope,validToken) {
console.log(validToken);
// Rest of controller code.
}
]);
I would like to do this without removing the []'s so the code could eventually be minifed. The below example is working as I expected so I know that all of my code it working, I'm just not sure what I should add to the above code to make it function similarly.
.controller('recoverCtrl', function($location,$scope,$http,$routeParams,$rootScope,validToken) {
console.log(validToken);
//Other code
});
Figured it out thanks to Etsus.
I just needed to add the object key as a string while injecting and it was able to determine that it was a resolve key
.controller('recoverCtrl', ['$location','$scope','$http', '$routeParams', '$rootScope', 'validToken', function ($location, $scope, $http, $routeParams, rootScope, validToken) {
console.log(validToken);
}]);

angularjs component with dynamic templateUrl

is it possible to create a AngularJS Component with a dynamic templateUrl?
Means I want to inject a service into the Component that gives me a base path to the template:
i.e.: templateUrl: configuration.baseScriptPath + '...html'
It is possible with a Directive, but how to do this with a Component?
angular.module('runtime')
.component('textInput', {
templateUrl: /*configuration.baseScriptPath + */'fd/components/text_input_instance.html',
controller: [
'$scope', '$element', 'focusInputGroup', 'configuration',
function ($scope, $element, focusInputGroup, configuration) {
Instead of templateUrl you can use template and ng-include, like this:
angular.module('runtime')
.component('textInput', {
template: '<div ng-include="getTemplate()">',
controller: [
'$scope', '$element', 'focusInputGroup', 'configuration',
function ($scope, $element, focusInputGroup, configuration) {
$scope.getTemplate = function () {
return configuration.baseScriptPath + 'fd/components/text_input_instance.html';
};
templateUrl property of component also takes a function. so you can try this,
angular.module('runtime')
.component('textInput', {
templateUrl: ['$configuration', function($configuration) {
return $configuration.basepath + '.html'
}],
controller: [
'$scope', '$element', 'focusInputGroup', 'configuration',
function($scope, $element, focusInputGroup, configuration) {

How to declare an angular-bootstrap modal in a way that is safe for minimization

I have implemented an angular modal dialog box following the guidelines given at: http://angular-ui.github.io/bootstrap/. The code below works fine when the non-minified files are accessed, but it fails when minification is applied. I have narrowed the problem down to the declaration of the modalInstanceCtrl function below, however I am not clear on how I can implement this function in a minification-friendly manner. I have tried to declare the modalInstanceCtrl function using standard controller syntax, but in that case, the function is not found by the $modal.open call.
The error message that I receive from the minified code is "TypeError: Cannot read property 'value' of undefined".
What is the best way to declare this controller so that it can be both minified as well as called from the $modal.open function?
Any help would be greatly appreciated.
lxModalSupportServices.factory('lxModalSupportService',
function ($modal, $log, $timeout) {
var modalInstanceCtrl = function($scope, $log, $modalInstance) {
$scope.ok = function () {
$modalInstance.close();
};
};
return {
showCameraAndMicrophoneModalWindow : function(scope, htmlTemplate) {
var ModalInstance = $modal.open({
templateUrl: htmlTemplate,
controller: modalInstanceCtrl
});
....
}
});
Change the declaration to
var ModalInstanceCtrl = [
'$scope', '$log', '$modalInstance',
function($scope, $log, $modalInstance) {
$scope.ok = function () {
$modalInstance.close();
};
}
];
and try again. If it still fails, probably the problem is somewhere else.
Normally I would declare the controller for $modal separately:
lxModalSupportServices.controller('AddCommentModalCtrl', ['$scope', function($scope) {
'use strict';
// Implementation...
});
Then use it with string
$modal.open({
templateUrl: htmlTemplate,
controller: 'AddCommentModalCtrl',
});

How can you manually inject route resolve data inside a controller?

I have 2 routes that share a controller, one needs data resolved prior to the view loading, and the other does not need the resolved data.
Routing segment example:
...
when('/users', {
controller: 'UsersCtrl',
templateUrl: '/partials/users/view.html',
resolve: {
resolvedData : ['Accounts', function(Accounts) {
return Accounts.get();
}]
}
}).
when('/users/add', {
controller: 'UsersCtrl',
templateUrl: '/partials/users/add.html'
})
...
Controller example:
app.controller('UsersCtrl', ['$scope', 'Helper', 'resolvedData',
function($scope, Helper, resolvedData) {
// this works for the first route, but fails for the second route with
// unknown "resolvedDataProvider"
console.log(resolvedData);
}]);
Is there any way I can get the resolvedData in the controller without explicitly using the resolve name as a dependency? So a check can be performed?
Using the $injector does not work. I would like to do something similar to:
if ($injector.has('resolveData')) {
var resolveData = $injector.get('resolveData');
}
However this does not work even for the route that has the resolveData set ('/users'):
app.controller('UsersCtrl', ['$scope', 'Helper', '$injector',
function($scope, Helper, $injector) {
// this does not work -> fails with the unknown "resolvedDataProvider" as well
$injector.get('resolvedData');
}]);
Can this be done in angularjs? Or should I just create a new controller?
Thank you.
Looks like I figured out another way to go. The resolved data is part of the $route. So you can access it using:
app.controller('UsersCtrl', ['$scope', '$route', 'Helper',
function($scope, $route, Helper) {
if ($route.current.locals.resolvedData) {
var resolvedData = $route.current.locals.resolvedData;
}
}]);
If the other route doesn't need it, just inject undefined on that route:
router:
when('/users', {
controller: 'UsersCtrl',
templateUrl: '/partials/users/view.html',
resolve: {
resolvedData : ['Accounts', function(Accounts) {
return Accounts.get();
}]
}
}).
when('/users/add', {
controller: 'UsersCtrl',
templateUrl: '/partials/users/add.html',
resolve: {
resolvedData: function() {
return undefined;
}
}
})
controller:
app.controller('UsersCtrl', ['$scope', 'Helper', 'resolvedData',
function($scope, Helper, resolvedData) {
if(resolvedData){
//set some scope stuff for it
} else {
//do what you do when there is no resolvedData
}
}]);

AngularJS: Load templateUrl after all data received by the controller

I'd like to display my template when the data coming from my server are loaded.
I created a module called Services with inside some services to load my data, I'm using HomeService for my example.
var app = angular.module('MyApp', ['Services']);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/',
{
templateUrl: 'home.html',
controller: 'Home_Ctrl',
resolve: {
loadData: //??
}
});
}]);
app.controller('Home_Ctrl', ['$scope', 'HomeService', function($scope, HomeService) {
$scope.data = HomeService.getData();
}
I guess I need to create a promise to do that. Is it possible to put this function inside my controller?
I mean, I don't want something like that:
var ctrl = app.controller('Home_Ctrl', ['$scope', 'HomeService', function($scope, HomeService) {
//Do something
}
//Promise
ctrl.fct = function($q) {
}
I want something like that:
app.controller('Home_Ctrl', ['$scope', '$q', 'HomeService', function($scope, $q, HomeService) {
//Do something
//Promise
this.fct = function() {}
}
Any idea?
Thanks.
You could use resolve property of controller.
You could create a object which will return promise and assign to controller resolve function and inject the same in controller definition kindly see very simple example
$routeProvider.when('/ExitPoll', {
templateUrl: '/partials/ExitPoll.html', controller: exitpollController, resolve: {
responseData: ['$http', function ($http) {
return $http.get('/Candidate/GetExitPolls/hissar').then(function (response) {
return response.data;
});
}],
}
});
var exitpollController = ['$scope', '$http','responseData','$rootScope',
function ($scope, $http, responseData, $rootScope) {
}];

Categories