passing scope parameters to resolve function angularjs - angularjs

I have a route provider with following configuration.
ocsApp.config(function($routeProvider){
$routeProvider
.when('/userStat/:pageNo' ,
{
templateUrl:'userStats',
controller:'userStatController',
resolve: {
loadData: searchController.loadData
}
});
});
The loadData function i.e resolve method calls a service which needs around 6-7 parameters that I do not want to appear in route URL and all these are available in searchController scope. Is there a way i can pass those parameters in loadData function.
Code is like this.
searchController.loadData=function($q,sessionFactory,$route){
var deferred = $q.defer();
sessionFactory.getSessions(siteId,startDate,endDate,pageNo,resultPerPage)
success(function(data,status)
{
deferred.resolve(data);
});
return deferred.promise;
};
is there a way to pass those parameters in loadData function.

The "searchController" scope doesn't really exist in the context you're thinking of.
What you should do is abstract the parameters currently in the searchController scope into a service, put your parameters there, and inject that into your loaddata function. If binding is important, you will either have to manually update that service's parameters based on $watch or you can put an object of parameters from the service into the searchController scope and regular binding will work.

Related

Testing a class that uses $inject property notation in its functions

I need to modify a constant service. This service has no tests attached, but I wanted to, at least partially, cover the file and my modifications with unit tests that I will write with Jasmine.
The service looks like:
(function () {
angular
.module('app')
.constant('myService', myService);
function myService() {
dependencyOne: dependencyOneImpl,
someFunction: someFunctionImpl
...
}
dependencyOneImpl.$inject = ['someDependency'];
function dependencyOneImpl(someDependency) {
...
}
someFunctionImpl.$inject = ['dependencyOne', 'dependencyTwo'];
function someFunctionImpl(dependencyOne, dependencyTwo) {
...
}
})();
It is used in the resolution process of routes (we use ui-router). When a particular route is activated, a function of the service is invoked:
someRoute = {
url: '...',
name: '...'
views: { ... },
resolve: { resolver.someFunction }
}
There are no dependencies required in the construction of the service, and I'm trying to test one of the public functions that the service exposes.
Typically I would write the test like:
prepareSomeSetup();
theService.someFunction();
assertSomething();
I could manually resolve the dependencies required by the function, but I would like to know if I can get the same behavior that ui-router is getting when resolving the function. The dependencies seem to be resolved and the function is executed.
It crossed my mind that I probably needed to inject $injector service in the test file and manually call invoke somehow to resolve the function, but it does not seem to work.
How can I call the function with the two dependencies resolved?
When you define an injectable function you have to call it using $injector.invoke(fn, scope, otherArgs);
Where
fn the injectable function, or array for inline injection
scope : the "this" of the function
otherArgs : others Arguments that are not defined as service,... in angular that you inject.

Can't set angular $scope variable from a callback function in Ionic

I am new in angular js. I am working with web Sql in a test project for learning purpose. My insert operation is working fine. My problem is when i fetch all the records then i can't store it in $scope.todos=results.rows
My code is
tx.transaction(sql,[],myCallback)
function myCallback(tx,results)
{
console.log(results.rows); // shows objects in console
$scope.todos=results.rows;
}
In view the todos is not working with ng-repeat.
It might help to show all of your controller, or service. If it's a controller make sure you included the $scope parameter for example:
.controller('MyController', function ($scope){
}))
If you are doing this inside a service, save it in a variable inside the service, then from a controller where the "$scope" is available include your service then call your variable containing the results. This will also be helpful if you need to share those results with other controllers at a later time.
.service('MyDataService',function(){
var todos;
return {
.... set and get functions to access variable ...
getTodos: function() {
return todos;
}
};
});
And in controller
.controller('MyController', function ($scope, MyDataService){
$scope.todos = MyDataService.getTodos()
}))
There are also ways to get the $scope working in a service but I don't think it's a great idea.

Angular Ui-router Resolve concept

I was reading the docs of ui-router but I couldn't grasp the concept of resolves for controllers in each state. I am not able to figure out where should we use resolve and why the controller attached to a state is not enough (as we can inject any dependencies in it we want) ?
I've tried going through docs and other tutorials several times but its quite confusing , Can someone please explain it with its real life application?
Imagine you want to create a modal and pass some data to it. I'm using the angular-ui-bootstrap modals for this example.
var openExampleModal = function () {
var modalInstance = $modal.open({
templateUrl: "Modal.html",
controller: "ModalController",
size: "lg"
});
return modalInstance.result;
};
Now if you want to pass some data to this modal on initialization, you can either save it in your $rootScope or some data service, or you can use resolve to inject it into your controller directly without having to use anything else.
var openExampleModal = function (myData) {
var modalInstance = $modal.open({
templateUrl: "Modal.html",
controller: "ModalController",
size: "lg",
resolve: {
sampleData: function () {
return myData;
}
}
});
return modalInstance.result;
};
and in your controller you would have:
MyController.$inject = ["sampleData"];
function Mycontroller(sampleData) {
//You can access the data you passed on via sampleData variable now.
};
Resolve is used to inject your own custom objects into the controller, not for injecting dependencies.
A resolve is simply a value that is passed to the controller upon instantiation (which are used like an injected value). The neat thing about them is that if the value returned is a promise, the view/controller won't load until the promise has resolved.
The way you use them is by adding a resolve key to your route state, and returning the object you want injected into your controller (also naming it). For example:
.state('example', {
url: '/page',
templateUrl: 'sometemplate.html',
controller: 'SomeCtrl',
resolve: {
injectionName: function(){
// return a value or promise here to be injected as injectionName into your controller
}
}
});
Then inside your controller you simply add the resolve name to the controller injected values:
.controller('SomeCtrl', function($scope, injectionName){
// do stuff with injectionName
});
Just note that if you do return a promise, the value that is injected is the result of the promise (not the promise itself). Also note that if the promise errors the view/controller will not load, and an error will be thrown. As #koox00 commented, this error will fail silently unless $stateChangeErrorError is handled (usually in your apps primary run() function).
So why would you use this? Well if not inferred from above, you do this usually when you want your view/controller to wait until some async process has completed before loading a particular state. This saves you from creating loaders or loading processes for every single view/controller, moving it to a simple definition of what needs to be loaded.
As said by Jean-Philippe you can use resolve if you want to load some data before switching to a certain state. Resolve waits and blocks until the data is arrived and only then the state transition is done.
It is an highly discussed topic whether using a resolve or loading the data on the fly within the controller. I would say: It depends on your use case :)
Further info from supercool todd motto: https://toddmotto.com/resolve-promises-in-angular-routes/

What is the best way to initiate an AngularJS controller function that uses a service that make an HTTP request

I'm new on AngularJS. I would like to know what is the best way to use pure AngularJS to initiate a controller that uses a service that makes an HTTP request to an external source and as a response receives a JSON object.
The controller is being used to fetch information that will be shown as part of the landing page (welcome information).
I have tried:
In the HTML invoke the function with the ng-init, with alias for the controller and without alias.
In the controller make the explicit call to the service, and in the configuration of routes, resolve primitive to call the Service and save it a a variable at the configuration file.
In the controller receive as a parameter the response of the service and in the configuration of routes, use the resolve primitive to call the Service and save it as a variable with the name of the parameter that the controller receives.
In the controller save the response as a $scope variable, but it is always undefined an nothing is bound to the HTML. Is it necessary to create a value or a directive or something for saving an object in the scope? Also tried doing it at the service with $scope as parameter with the same results (undefined $scope variable).
These options effectively trigger the HTTP request and pass through the lines of the controller function. The problem is that the response is not available for the controller. Under debug mode I can only see that is an object but it doesn't behaves as a JSON object so can't access to none of the properties.
I used the .then at the controller, but although now the data is saved in the $scope, it shows [OBJECT OBJECT] and I can't access to the properties of the JSON object that is saved as the response of the http request. Any ideas?
The function of the service that makes the request like the following:
myAppModule.factory('ClimateService', function ($http) {
return {
getLocation: function () {
return $http.get("some_url/json")
then(function successCallback(response) {
return response.data;
}, function errorCallback(response) {
//
});
}
}
});
Under debug I can see the 200 response and the JSON of it. Content-Type:application/json; charset=utf-8
After several changes, none of them are triggering and I am getting an injection error. I have included the local angular-routes in the HTML header, fetched with bower.jason to the project at NetBeans. And included as the first dependency or parameter to the ngRoute
angular.module('app',['ngRoute', ...
angular.module('app.routes', ['ngRoute', 'app.core'])
.config(config);
angular.module('app.core', []);
By the way, the Angello project at GitHub injects neither services nor much parameters and the book doesn't cover this topic in depth.
Is it the version of AngularJS?
Uncaught Error: [$injector:modulerr]
http://errors.angularjs.org/1.4.8/$injector/modulerr?p0=app&p1=Error%3A%20%5B%24injector%3Amodulerr%5D%20http%3A%2F%2Ferrors.angularjs.org%2F1.4.8%2F%24injector%2Fmodulerr%3Fp0%3Dapp.config%26p1%3DError%253A%2520%255B%2524injector%253Anomod%255D%2520http%253A%252F%252Ferrors.angularjs.org%252F1.4.8%252F%2524injector%252Fnomod%253Fp0%253Dapp.config%250A%2520%2520%2520%2520at%2520Error%2520(native)%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A8383%252Fapp_demo_app%252Fbower_components%252Fangular%252Fangular.min.js%253A6%253A416%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A8383%252Fapp_demo_app%252Fbower_components%252Fangular%252Fangular.min.js%253A24%253A186%250A%2520%2520%2520%2520at%2520b%2520(http%253A%252F%252Flocalhost%253A8383%252Fapp_demo_app%252Fbower_components%252Fangular%252Fangular.min.js%253A23%253A251)%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A8383%252Fapp_demo_app%252Fbower_components%252Fangular%252Fangular.min.js%253A23%253A494%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A8383%252Fapp_demo_app%252Fbower_components%252Fangular%252Fangular.min.js%253A38%253A117%250A%2520%2520%2520%2520at%2520n%2520(http%253A%252F%252Flocalhost%253A8383%252Fapp_demo_app%252Fbower_components%252Fangular%252Fangular.min.js%253A7%253A333)%250A%2520%2520%2520%2520at%2520g%2520(http%253A%252F%252Flocalhost%253A8383%252Fapp_demo_app%252Fbower_components%252Fangular%252Fangular.min.js%253A37%253A488)%250A%2520%2520%2520%2520at%2520http%253A%252F%252Flocalhost%253A8383%252Fapp_demo_app%252Fbower_components%252Fangular%252Fangular.min.js%253A38%253A134%250A%2520%2520%2520%2520at%2520n%2520(http%253A%252F%252Flocalhost%253A8383%252Fapp_demo_app%252Fbower_components%252Fangular%252Fangular.min.js%253A7%253A333)%0A%20%20%20%20at%20Error%20(native)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8383%2Fapp_demo_app%2Fbower_components%2Fangular%2Fangular.min.js%3A6%3A416%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8383%2Fapp_demo_app%2Fbower_components%2Fangular%2Fangular.min.js%3A38%3A391%0A%20%20%20%20at%20n%20(http%3A%2F%2Flocalhost%3A8383%2Fapp_demo_app%2Fbower_components%2Fangular%2Fangular.min.js%3A7%3A333)%0A%20%20%20%20at%20g%20(http%3A%2F%2Flocalhost%3A8383%2Fapp_demo_app%2Fbower_components%2Fangular%2Fangular.min.js%3A37%3A488)%0A%20%20%20%20at%20http%3A%2F%2Flocalhost%3A8383%2Fapp_demo_app%2Fbower_components%2Fangular%2Fangular.min.js%3A38%3A134%0A%20%20%20%20at%20n%20(http%3A%2F%2Flocalhost%3A8383%2Fapp_demo_app%2Fbower_components%2Fangular%2Fangular.min.js%3A7%3A333)%0A%20%20%20%20at%20g%20(http%3A%2F%2Flocalhost%3A8383%2Fapp_demo_app%2Fbower_components%2Fangular%2Fangular.min.js%3A37%3A488)%0A%20%20%20%20at%20eb%20(http%3A%2F%2Flocalhost%3A8383%2Fapp_demo_app%2Fbower_components%2Fangular%2Fangular.min.js%3A41%3A249)%0A%20%20%20%20at%20c%20(http%3A%2F%2Flocalhost%3A8383%2Fapp_demo_app%2Fbower_components%2Fangular%2Fangular.min.js%3A19%3A463) (23:05:42:235 | error, javascrip
It's a bit tricky because you have to use promises (.then), but here's a super simple 'get' example.
On the Service:
function mainService($http) {
this.getData = function () {
return $http.get('/api/yourUrl') //a basic 'get' api call
.then(function (response) { //it takes time, so include a promise
return response.data;
});
};
}
And the Controller:
function homeController($scope, friendService) {
$scope.getData = function () {
mainService.getData()
.then(function (data) { //you also need a promise on controller
$scope.ourData = data; //finally put what you get on your scope
});
};
}
Note these examples don't show the defining of the controller and the service - let me know if you're confused.
let's suppose you'll use $http service to request data.
angular.module('app.core', [])
.controller('CoreController', CoreController);
CoreController.$inject = ['$scope', '$http'];
function CoreController($scope, $http) {
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
$scope.data = response.data;
}, function errorCallback(response) {
alert('something odd happens.');
});
};
in your html
<div ng-bind-html="data">
</div>
or if you want to fill a form input:
<input type="text" ng-model="data" />
From what I understood, I am suggesting few things to keep in mind . May be its not what you are looking for but it might help.
ng-init is called as the very first thing inside a controller. You can use promise in case you have to keep things in sync.
If you dont want to get into promise, simply do $http call from controller as it by default handles promise using .success & .error function.
You can't expect some $scope variable to be valid under html if it is inside service. Refer docs.
var mainApp = angular.module("mainApp",[]);
mainApp.controller("serviceController",function($scope,$http){
$http.get("/fetchData_url/").success(function(response){
$scope.data = response;
});
});

How to get the current route's controller (or scope)?

I have a controller that needs a thing provided by a route resolve function:
$routeProvider.when('/some/url', {
controller: MyController,
controllerAs: 'myCtrl',
resolve: {
theAnswer: ['deepThought', function(deepThought) {
return deepThought.computeTheAnswerAndReturnAPromise();
}]
}
});
var MyController = ['$route', function($route) {
this.theAnswer = $route.current.theAnswer;
}];
Now I want to do an end-to-end test, checking that the route matches and that parameters are propagated properly:
// ...set up the routes...
$location.path('/some/url');
$rootScope.$digest();
var ctrl = ???;
expect(ctrl.aThing).toBe(42);
In the non-test setup, I can put in a log statement and see that the controller is being created successfully and gets the correct data injected. The only problem is: how to get hold of the controller in the test?
There is $route.current.controller, but it contains the controller's constructor function and not the controller instance.
The documentation promises a $route.current.locals.$scope, from which I could get myCtrl, but the $scope property doesn't actually exist unless we also use ngView (it gets set here).
The controller isn't registered with any module, so I can't use $provide to intercept its creation and stash the controller somewhere.
Found it, thanks to #PSL's comment. The thing that actually constructs the controller is the ngView link function. We can fake that easily enough:
var ctrl = $controller(MyController, $route.current.locals);

Resources