Is it possible to call a factory service from a controller that it's been located on a different js file (an example will be nice), or the controller and factory service have to be on the same file ?
Thanks
You can include both scripts in index.html and then use the service in your controller:
index.html
<script src="js/pictures/picture.service.js"></script>
<script src="js/pictures/controllers/pictures.js"></script>
Here is the service picture.service.js:
(() => {
angular.module('gallery').factory('Picture', ['$http', 'Upload', function ($http, Upload) {
return {
all: () => {
return $http.get('/api/pictures');
},
findById: (id) => {
return $http.get(`/api/pictures/${id}`);
},
create: (picture) => {
return Upload.upload({
url: '/api/pictures/create',
data: picture
});
}
};
}]);
})();
Here is the controller where I am injecting the service:
(() => {
angular.module('gallery').controller('Pictures', ['Picture', function (Picture) {
let pictures = this;
// You might want to use .then instead of .success (deprecated)
Picture.all().success((data) => {
pictures.pictures = data;
});
}]);
})();
Here is an example github repo with a simple MEAN stack project.
https://github.com/NikolayKolibarov/MEAN-Simple-Gallery
Related
So, I am doing VERY SIMPLE controller like I've done before on my personal website I made back 8 years ago.
What I'm facing is an enormous app with code that followed no coding standards.
Here's my controller, inside a controller.js file:
app.controller("documentController", ["$scope", "documentService", ($scope, documentService) => {
let docCtrl = $scope;
//docCtrl = 'Hello World!';
docCtrl.docContent = [];
console.log('DOC CONTROL: ', docCtrl.content);
docCtrl.fetchDocs = function () {
documentService.getDocuments().then(function (result) {
docCtrl.docContent = result.data;
console.log('DOCS RETRIEVED: ', docCtrl.docContent);
});
}
docCtrl.fetchDocs();
}]);
and the service I need call inside a service.js file that's in the same module folder.
app.service('documentService', ["$http", "URL", ($http, URL) => {
let getDocuments = function () {
return $http.get(URL)
.success(function (data) {
console.log('SUCCESS: Documents retreived', data);
return data;
})
.error(function (e) {
console.log(`He's dead Jim!`, e);
return e;
})
}
return ({
getDocunment: getDocuments
});
}]);
Inside that controller.js file is a 2584 line controller set up the same way as my very simple controller that calls an 1000 line service in the service.js file.
My code sits at the bottom.
What happens is, when I run the app, I get UNK Provider error for the service.
Oh, I have a directive that also sits in the controller.js which is found and works.
app.directive("documentDirective", ["$compile", ($compile) => {
let data = {};
data.restrict = 'AE';
data.link = async ($scope, $element) => {
const template = '<span>Hello World!</span>'
await $element.html('').append($compile(template)($scope));
};
return data;
}]);
So, when I take out the call to the service, which I need, I get no errors.
When I put the service in the app.controller() that already exists in the controller.js file and call it, I still get UNK Provider. This makes ABSOLUTELY no sense.
[$injector:unpr] http://errors.angularjs.org/1.5.7/$injector/unpr?p0=URLProvider%20%3C-%20URL%20%3C-%20documentService
My personal website: www.peterborreggine.us, if you open the debug console and view: the Angular folder --> Controllers and Services, you'll see how I'm doing exactly what I am trying to accomplish here.
Of note, there are 65 module folders in the module directory all with their own controller.js and service.js. But only one controller and one service per file is there.
Again, I've been using Angular since its inception and now on Angular 12. This telecom company needs to upgrade to at least Angular 12
UPDATE:
I just tried this with the same UNK Provider error and this is suggested in Angular's error above! I combined both the service and controller and STILL the same error
// Combined Service and then my Controller
app.service('documentService', ["$http", "URL", ($http, URL) => {
let getDocuments = function () {
return $http.get(URL)
.success(function (data) {
console.log('SUCCESS: Documents retreived', data);
return data;
})
.error(function (e) {
console.log(`He's dead Jim!`, e);
return e;
})
}
return ({
getDocunment: getDocuments
});
}]).controller("documentController", ["$scope", "documentService", ($scope, documentService) => {
let docCtrl = $scope;
//docCtrl = 'Hello World!';
docCtrl.docContent = [];
console.log('DOC CONTROL: ', docCtrl.content);
docCtrl.fetchDocs = function () {
documentService.getDocuments().then(function (result) {
docCtrl.docContent = result.data;
console.log('DOCS RETRIEVED: ', docCtrl.docContent);
});
}
docCtrl.fetchDocs();
}]);
everyone. I need help with such problem.
I have such code for my angular 1.x app.js:
angular.module('app', []);
angular.module('app.test', ['app'])
.config(($stateProvider) =>
$stateProvider.state('base', {
url: '/',
controller: 'TestStateCtrl',
resolve: {
authenticationCheck: ['angularNg1Service', angularNg1Service=> {
angularNg1Service.test1();
}]
}
})
})
.run((angularNg1Service) => {
angularNg1Service.test2();
});
Here is the code of my angularNg1Service:
angular.module('app')
.service('angularNg1Service',
function (angularNg2Service} {
//some code here
}
My angularNg2Service is downgraded before .run function of angular 1.x module starts:
window['angular']
.module('app')
.factory(
'angularNg2Service',
upgradeAdapter.downgradeNg2Provider(AngularNg2Service)
);
But, I have an error message :
Cannot read property 'injector' of null
When .run function of angular 1.x module starts.
Here is my main.ts file:
import { upgradeAdapter } from './upgradeAdapter';
import { bootstrapNg1Components } from './app/ng1Components';
bootstrapNg1Components(upgradeAdapter);// this function downgarades my AngularNg2Service
upgradeAdapter.bootstrap(document.querySelector('html'), ['app.start']);
I have read some similar problems but don't find any solution.
Also I have a lot of Angular2 Services which are downgraded.But the problem is just for one particular service that is injected into Angular1 Service that is used in .run function.
You can use workaround described here https://github.com/angular/angular/issues/10992:
put your run code in setTimeout function.
angular.module('app.test', ['app'])
...
.run(($injector) => {
setTimeout(function() {
var angularNg1Service = $injector.get('angularNg1Service');
angularNg1Service.doSmth();
// downgraded angularNg2Service is available here
// inside of async function that will run after module.run method
var angularNg2Service = $injector.get('angularNg2Service');
},0);
});
To be sure the application state does not start before application is configured (that performed in run method) you can add resolve for every state.
angular.module('app.test', ['app'])
.config(($stateProvider) =>
$stateProvider.state('base', {
url: '/',
controller: 'TestStateCtrl',
resolve: {
appBootstrapped: ['appBootstrapStateService', () => {
return appBootstrapStateService.statePromise;
]},
authenticationCheck: ['angularNg1Service', 'appBootstrapped', (angularNg1Service, appBootstrapped) => {
angularNg1Service.test1();
}]
}
})
})
And to make it works you should change bootstraped state at the end of module.run method
angular.module('app.test', ['app'])
...
.run(($injector) => {
setTimeout(function() {
...
var appBootstrapStateService = $injector.get('appBootstrapStateService');
appBootstrapStateService.complete(); // allow state work
},0);
});
appBootstrapStateService is angularJS service like
angular.module('app')
.service('appBootstrapStateService', function () {
const stateSubject = new Rx.Subject();
this.statePromise = stateSubject.asObservable().toPromise();
this.complete = () => {
stateSubject.complete();
};
});
I've just started using Angular alongside RequireJs and so far I have created a structure that looks like this:
app.js
app.core.js
app.controllers.js
app.services.js
The core module is where I hinge dependencies and pull in the services and controller modules, like this for example:
(function () {
var dependancies = ['angular'];
define(dependancies, function (angular) {
return angular.module('app.services', [])
.factory('VehicleService', ['$injector', function ($injector) {
var stub = {};
require(['../Angular/Services/VehicleService'], function (VehicleService) {
angular.extend(stub, $injector.invoke(VehicleService));
});
return stub;
}]);
});
})();
And each service is created in its own file like so:
(function () {
define(function () {
return ['$http', function ($http) {
return {
getAllMakes: function () {
return $http.get('/Api/RegisteredVehicle/GetAllMakes')
.success(function (response) {
return {
vehicleName: response
}
});
}
};
}];
});
})();
How can I now use $stateprovider.state.resolve and get my service instantiated correctly?
.state('quote', {
url: '/quote',
templateUrl: '/Sales/Dashboard/CreateQuoteVehicle',
controller: 'QuoteProposalCtrl as vm',
resolve: {
vehicleInfo: function () {
var stub = {};
require(['../Angular/Services/VehicleService'], function (VehicleService) {
angular.extend(stub, $injector.invoke(VehicleService));
});
return stub;
}
}
})
On your core angular module, inject $stateProvider, then put in the states. It should pull in the rest of your dependancies. This should then be loaded as the main starting requirejs file.
(function () {
var dependancies = ['angular', 'app.core', 'app.controllers', 'app.services'];
define(dependancies, function (angular) {
var app = angular.module('myApp', ['app.core', 'app.controllers', 'app.services']);
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('quote', {
url: '/quote',
templateUrl: '/Sales/Dashboard/CreateQuoteVehicle',
controller: 'QuoteProposalCtrl as vm',
resolve: {
vehicleInfo: function () {
var stub = {};
require(['../Angular/Services/VehicleService'], function (VehicleService) {
angular.extend(stub, $injector.invoke(VehicleService));
});
return stub;
}
}
})
});
return app;
})();
Depending on your setup you'd be loading the app something like:
<script data-main="scripts/app" src="scripts/require.js"></script>
One thing, im not sure you need this require, since it should already be loaded with the app.services dependancy.
var stub = {};
require(['../Angular/Services/VehicleService'], function (VehicleService) {
angular.extend(stub, $injector.invoke(VehicleService));
});
return stub;
I am starting to learn angularjs, so far i can create update delete withoud using services. I am trying to take it to the next level: Ive created a service page that looks like this:
app.factory('MainService', function($http) {
var getFeaturesFromServer = function() {
return $http.get('restfullfeatures/features');
}
var deleteFeature = function(id) {
return $http.post('restfullfeatures/delete', {'id': id});
}
var createFeature = function(feature) {
return $http.post('restfullfeatures/create', {'title': feature.title, 'description': feature.description});
}
return {
getHello : getHello,
getFeatures: getFeaturesFromServer,
deleteFeature: deleteFeature,
createFeature: createFeature
}
});
and my add function in controller looks like this:
$scope.add = function(){
MainService.createFeature($scope.formFeature)
.then(function(response) {
console.log('feature created',response.data);
$scope.features.push($scope.formFeature);
$scope.formFeature = {};
}, function(error) {
alert('error',error);
});
};
And this is my postCreate function:
public function postCreate()
{
\App\Feature::create(
['title' => \Input::get('title'),
'description' => \Input::get('description')
]);
return ['success' => true];
}
I have a table in my database called features, so basically what i am trying to do is add a new feature to my table using angularjs, my controller doesnt seem to recognize formFeature all i get is 'undefined' then i get the error: Cannot read property of type undefined, but I am using it in my delete function and it works perfectly, what did i miss here??
Factory
So when creating a factory for CRUD, try to lay out your factory like the example below. The example is some code I wrote for a project each call willl do a different thing, the idea is that you add a method that you can instantiate when you add the factory to your controller. (note: don't use $rootScope for session)
.factory('Chats', function ($http, $rootScope, $stateParams) {
return {
all: function () {
return $http.get('http://your_ip/chats', { params: { user_id: $rootScope.session } })
},
get: function () {
return $http.get('http://your_ip/chat', { params: { user_id: $rootScope.session, chat_id: $stateParams.idchat } })
},
add: function (id) {
return $http.post('http://your_ip/newChat', { params: {idfriends:id}})
}
};
});
Controller
when you instantiate this in your controller your looking at something like this
.controller('ChatsCtrl', function ($scope, Chats) {
Chats.all().success(function (response) {
$scope.chats = response;
});
$scope.getChat = function (id) {
Chats.get().success(function (response) { })
};
$scope.addChat = function (id) {
Chats.add(id).success(function (response) { })
};
})
$scope.remove and $scope.addChat and linked to buttons that will execute on click and $scope.chats is bound to the page via an ng-repeat.
Conclusion
Clean up your factories to look like this and you can easily write a series of reusable methods that are easy to instantiate in your controller.
In my angular app I have a view, a controller and a service.
The service load resources ex:service load persons and initialize value with the result.
I want to load my view after my service finish his function to load his resources.
var myApp = angular.module('myApp',[]);
myApp.controller('PersonsCtrl', ($scope, Persons) {
$scope.persons = Persons.data;
});
myApp.factory('Persons', {
data: [[function that load resources => take time]]
});
So I want to load my controller when my service finish his initialization.
Some ideas?
Assuming you have a route provider, here's a basic example. When the promise is resolved, "personData" will be injected into your controller. There's not much info about what your service does, so I had to give something very generic.
myApp.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/persons', {
controller: 'PersonsCtrl',
templateUrl: 'persons.html',
resolve: {
personData: ['Persons', function(Persons) {
return Persons.getData();
}]
}
});
}]);
myApp.controller('PersonsCtrl', ($scope, personData) {
$scope.persons = personData;
});
myApp.factory('Persons', {
getData: function() {//function that returns a promise (like from $http or $q)};
});
Maybe try using promises, example below
var myApp = angular.module('myApp',[]);
myApp.controller('PersonsCtrl', ($scope, Persons) {
$scope.persons = Persons.getData().then(function(response){
//do whatever you want with response
});
});
myApp.factory('Persons', function ($http, $q) {
return {
getData: function () {
var def = $q.defer();
$http.get('url').
success(function (response) {
def.resolve(response);
})
return def.promise();
}
}
});