I'm running into that annoying Angular minify problem (I really hope this issue is non-existent in Angular 2)
I've commented out all my app module injections and going down the list 1 by 1 to find out where the problem is and I think I narrowed it down to my searchPopoverDirectives:
Can you see what I'm doing wrong?
Original code, produces this error Unknown provider: eProvider <- e:
(function() { "use strict";
var app = angular.module('searchPopoverDirectives', [])
.directive('searchPopover', function() {
return {
templateUrl : "popovers/searchPopover/searchPopover.html",
restrict : "E",
scope : false,
controller : function($scope) {
// Init SearchPopover scope:
// -------------------------
var vs = $scope;
vs.searchPopoverDisplay = false;
}
}
})
})();
I then tried the [] syntax in an attempt to fix the minify problem and ran into this error Unknown provider: $scopeProvider <- $scope <- searchPopoverDirective:
(function() { "use strict";
var app = angular.module('searchPopoverDirectives', [])
.directive('searchPopover', ['$scope', function($scope) {
return {
templateUrl : "popovers/searchPopover/searchPopover.html",
restrict : "E",
scope : false,
controller : function($scope) {
// Init SearchPopover scope:
// -------------------------
var vs = $scope;
vs.searchPopoverDisplay = false;
}
}
}])
})();
UPDATE:
Also found out this guy is causing a problem:
.directive('focusMe', function($timeout, $parse) {
return {
link: function(scope, element, attrs) {
var model = $parse(attrs.focusMe);
scope.$watch(model, function(value) {
if (value === true) {
$timeout(function() {
element[0].focus();
});
}
});
element.bind('blur', function() {
scope.$apply(model.assign(scope, false));
})
}
}
})
When you minify code, it minify all code, so your
controller : function($scope) {
was minified to something like
controller : function(e) {
so, just use
controller : ["$scope", function($scope) { ... }]
When minifying javascript the parameter names are changed but strings remain the same.
You have 2 ways that you can define which services need to be injected:
Inline Annotation:
phonecatApp.controller('PhoneListCtrl', ['$scope', '$http', function($scope, $http){
...
}]);
Using the $inject property:
phonecatApp.controller('PhoneListCtrl', PhoneListCtrl);
PhoneListCtrl.$inject = ['$scope', '$http'];
function PhoneListCtrl($scope, $http){
...
}
Using $inject is considered more readable than inline annotations. It is best practice to always have one line declaring the controller, service, or directive, one line for defining the injection values, and finally the implementation method. The method may be defined last due to the hoisting nature of javascript.
Remember: The order of your annotation (strings) and your function parameters must be the same!
Related
I have a simple controller that works just fine:
app.controller('IndexController', ['$scope', obj.indexPage]);
var obj = {};
obj.indexPage = function ($scope) { // do controller stuff };
I also have an event function that i want to use to load/create/instantiate this controller:
// some callback, doesn't really matter
app.onPage('index', function () {
// load and run controller logic in here
app.controller('IndexController', ['$scope', obj.indexPage]);
}, obj);
there are some issues, like Argument 'IndexController' is not a function, got undefined
Any ideas?
my solution:
app.controller('IndexController', ['$scope', function ($scope) {
var obj = {};
obj.indexPage = function (data) {
// do controller stuff
};
app.onPage('index', function (data) {
obj.indexPage(data);
}, obj);
});
Due to how the angular module system works, you can't instantiate controllers asynchronously like that. You can however, use the $controller service to create controllers on the fly. The same technique below is often used in unit testing.
For example:
angular.module('app', [])
.controller('MyCtrl', function($rootScope, CtrlFactory){
var dynamicCtrl = CtrlFactory.create({$scope: $rootScope.$new()});
console.log(dynamicCtrl.method()); //-> 123
})
.factory('CtrlFactory', function($controller) {
return {
create: function(locals) {
return $controller(
//this is the constructor of the new controller
function($scope){
console.log('Dynamic controller', $scope);
this.method = function() { return 123; };
},
//these are the injected deps
locals
);
}
};
})
For some example usage in a unit testing context, see: https://docs.angularjs.org/guide/controller.
I'll add that you may want to reconsider your reasons for doing this--I can't say I've seen $controller used outside testing.
app.onPage('index', function () {
app.controller('IndexController', obj.indexPage); // this would load the controller to the module
$controller('IndexController', { $scope: $scope }); // This would instantiate the controller, NOTE: $controller service should be injected
}, obj);
I have an angular project that I'm breaking out into a better file structure but I'm getting Argument 'fn' is not a function, got undefined for an error when creating a new service. Any ideas what I'm doing wrong?
app.js
angular.module('app', [
'app.controllers'
]);
angular.module('app.controllers', ['leaflet-directive', 'app.services']);
angular.module('app.services', []);
main.controller.js
angular.module('app.controllers')
.controller('MainCtrl', MainCtrl);
function MainCtrl($scope, $window, leafletData, DataService) {
var main = this;
main.items = DataService.GetItems();
//Other controller stuff
};
data.service.js
angular.module("app.services")
.factory('DataService', DataService);
var DataService = function(){
return data = {
getItems: function(){
return [//data here];
}
};
}
Your declaration of DataService is the problem. You're declaring it after you're using it. You should change your declaration of DataService to function DataService() instead of setting it to a var to take advantage of function hoisting
I 'm trying to handle data that is coming from my database in a directive , however these data are being pulled by a controller and being assigned to scope like this:
Calendar Controller:
'use strict';
var CalendarController = ['$scope', 'EventModel', function(scope, EventModel) {
scope.retrieve = (function() {
EventModel.Model.find()
.then(function(result) {
scope.events = result;
}, function() {
});
}());
}];
adminApp.controller('CalendarController', CalendarController);
Calendar Directive:
'use strict';
var calendarDirective = [function($scope) {
var Calendar = {
init: function(events) {
console.log(events);
}
};
return {
link: function(scope) {
Calendar.init(scope.events);
}
};
}];
adminApp.directive('calendarDirective', calendarDirective);
But the data is undefined in the directive, and in the controller the data appears to be ok.
Thanks!
This is a common error for people starting out with AngularJS. This is a load order issue. The events scope variable is not defined when the directive link function is executed. One solution is to use a watch on the variable passed into the directive and load once it is defined.
return {
link: function(scope) {
scope.$watch('events', function() {
if(scope.events === undefined) return;
Calendar.init(scope.events);
});
}
};
In the above scenario controller and directives have isolated scope. One solution will be to use factory/service to communicate with the server and inject the service to controller and directive. Since service/factory is singleton you can cache the data & share is between controllers & directives.
try this way.
Directive html
<calendar-directive objEvent="events" ></calendar-directive >
JS :
'use strict';
var calendarDirective = [function($scope) {
return {
scope : { objEvent : '=objEvent'}
template: '<div>{{ objEvent }}</div>',
};
}];
Use angular isolated scopes.
I have here my javascript code:
define(['controllers/controllers', 'services/alerts'], function(module) {
'use strict';
return module.controller('alerts', [
'$scope', '$http', 'alerts', function($scope, $http, alerts) {
console.log('alerts controller initialized');
$scope.settings = {};
return $scope.submit = function() {
$scope.busy = true;
console.log('scope', $scope);
return console.log('data', $scope.data);
};
}
]);
});
I tried to log the contents of $scope.data that I expect to contain the values of ng-model => data.followers but always show undefined but when I tried to log value contents of $scope, $scope.data exists. As shown in the image:
I tried initializing $scope.data but it will always return an empty array after changing the value of ng-model => data.followers. This is the code (in haml) when I initialized ng-model:
%input{:type => "checkbox", "ng-checked" => "settings.#{$key}", "ng-model" => "data.#{$key}", "ng-true-value" => "true", "ng-false-value" => "false", "ng-click" => "submit()"}
Any thoughts?
UPDATE:
Already fix this. All I did was to initialize $scope.data and used data.#{$key} in the ng-checked. That got me stuck. Noob angular programmer here.
When lazy loading Angular components, you need to use $scope.$apply(). When components are lazy loading using Require, or some other method, the functions are registered onto teh $scope outside of the $digest loop of Angular. using $scope.$apply() makes the $digest aware of your bindings, and brings them inside the app instance.
You will likely also need to use module.register.controller instead of module.controller
define(['controllers/controllers', 'services/alerts'], function(module) {
'use strict';
return module.register.controller('alerts', [
'$scope', '$http', 'alerts', function($scope, $http, alerts) {
console.log('alerts controller initialized');
$scope.settings = {};
return $scope.submit = function() {
$scope.busy = true;
console.log('scope', $scope);
return console.log('data', $scope.data);
};
$scope.$apply();
}
]);
angular.module('app.services', []).service("test", function($http, $rootScope){
this.test=function(){
$rootScope.name="test1";
};
};
angular.module('app.controllers', []).controller('TestController', function ($scope, test) {
test.send();
})
I dont get an error but the changes don't get applied to the UI. I tried $scope.apply() and got an error.
We need to tell Angular which modules your module depends on, In our case the main module is app.controllers.
To call service from different model we need tell to controller where is our service:
['app.services']
JS
var appServices = angular.module('app.services', []);
var appCtrl = angular.module('app.controllers', ['app.services']);
appServices
.service("test", function ($http, $rootScope) {
this.send = function () {
$rootScope.name = "test1";
};
});
appCtrl.controller('TestController', function ($scope, test) {
test.send();
});
Demo Fiddle
I think you should change ".service" by ".factory".
As I can see in the creating services docs there are 3 ways of creating custom services. One of then is using factory way, as the following:
var myModule = angular.module('myModule', []);
myModule.factory('serviceId', function() {
var shinyNewServiceInstance;
//factory function body that constructs shinyNewServiceInstance
return shinyNewServiceInstance;
});
Hope to help.