Hi I have small factory (myFactory) in my application:
.factory('myFactory', ['$q', function ($q) {
function myMethod() {
.....
}
return {
myMethod: myMethod
};
}]);
I want to get access to myFactory.myMethod() in protractor test so in onPrepare() I'm using
browser.executeScript(function() {
return angular.element(document).injector().get('myFactory');
}).then(function (myFactory) {
console.log('myFactory: ', myFactory);
myFactory.myMethod();
});
for console.log('myFactory: ', myFactory) I see I get object:
myFactory: {
myMethod: {}
}
Then for myFactory.myMethod(); I see error:
TypeError: object is not a function
Anyone know how I can get access to factory from protractor to be able to execute method?
I use services to access user information in my app via Protractor, I went ahead and played around with this as close to your code as I could, my comment above should be your solution. Here's the longer explanation:
So we have a service Users, with a function called getCurrent() that will retrieve the information of the current user. So first time I tried code similar to yours:
browser.executeScript(function () {
return angular.element(document.body).injector().get('Users');
}).then(function (service) {
console.log(service); // logs object which has getCurrent() inside
service.getCurrent(); // error, getCurrent() is not a function
});
This logged the Users object, and included the function getCurrent(), but I encountered the same error as you when I tried to chain the call service.getCurrent().
What DID work for me, was simply moving the .getCurrent() into the execute script. i.e.
browser.executeScript(function () {
return angular.element(document.body).injector().get('Users').getCurrent();
}).then(function (service) {
console.log(service); // logs John Doe, john.doe#email.com etc.
});
So applying that to your case, the below code should work:
browser.executeScript(function() {
return angular.element(document).injector().get('myFactory').myMethod();
}).then(function (myFactory) {
console.log(myFactory); // this should be your token
});
And just a minor FYI, for what it's worth you also could have written this code by passing in a string to executeScript:
browser.executeScript('return angular.element(document).injector().get("myFactory").myMethod()').then(function (val) {
console.log(val);
});
Related
I am using 2 service in controller
First Service is to get AjaxResponse where logic to fetching the response is mentioned
The second Service calls the first service to make Http request and get result and then, in turn, return it to the controller
Ctrl Dependency injected firstService,secondService
this.getService = secondService.getData(param);
First Service--> firstService
this.httpResponse(param){
var re = $http.get(param);
return re.then(success,fail);
}
function success(data){
return data;
}
function fail(data){
console.log(data);
}
Second Service (Dependency injection of First Service)
function secondService(firstService){
this.getData = function(param){
return firstService.httpResponse(param);
};
}
this.getService is coming as undefined, all the call are going properly.
Even tried the following code:
secondService.getData(param).then(function(data){console.log(data);});
That doesn't help either.
You should chain the promises in these kinds of situations.
First, you define your service. It should contain two distinct functions. As an example, I did a GET and a POST.
angular.module("myApp",[]).factory("SharedServices", function($http) {
return {
getItem: function() {
return $http.get('path/to/api');
},
postItem: function(payload) {
return $http.post('path/to/api', payload);
}
};
});
Then, reference the service in your controller. getItem() will return a promise, where you can use it using .then to call your second service in the success callback.
angular.module("myApp",[]).controller("MainCtrl", function($scope, SharedServices) {
SharedServices.getItem().then(function(response) {
//success, got something
//call the second part
var payload = { myPayload: response.data.someItem };
SharedServices.postItem(payload).then(function(response) {
//success
}, function(response) {
//an error has occurred to the second call--POST
});
}, function(response) {
//an error occurred to the first call--GET
});
});
Used Callback to get the result.It is similar to deferred(promise)
I want to include Asp.Net Identity into my app.
But when I want to register a new user, I get an error on javascript side:
Cannot read property 'then' of undefined.
This is the code in my Controller: When I click the button to register the user, I get in the function below.
$scope.signUp = function () {
AuthenticationService.register($scope.registerData).then(function (response) {
...
},
function (response) {
...
});
};
And this is the code in my Service, which is called in the Controller above.
register: function (registerData) {
this.logout();
Restangular.all('api/account/register').post(registerData);
}
What am I doing wron? Can you help me to get the solution?
Your service method does not return the promise of what Resangular.all().post() is supposed to return. Its a q promise.
register: function (registerData) {
this.logout();
return Restangular.all('api/account/register').post(registerData);
//return $http.post("api/account/register", {data:registerData})
}
I am trying to run the following code before any of my AngularJS app controllers, directives run, but unfortunately the app main page controller loads before this code finish executing, so I was wondering if there is a way to ensure that all my app controllers, directives won't run / load before this code finish completely? Thanks
myApp.run(['TokenSvc',function (TokenSvc) {
TokenSvc.getToken().then(function(serverToken){
console.log('Got it...');
}, function(status){
console.log(status);
});
}]);
Most commonly you'll see resolve in the ng-route or ui-router $state definition used for this concern, but that can be problematic. If the resolution takes a while, the user will just be staring at a blank screen. Of course, you can mitigate this problem by using an interceptor to display a loader, but I'd argue that that's outside the intended utility of interceptors.
I like to use something to manage the initialization promise(s), and inject that thing into top-level Controllers (i.e. either a Mediator or Observer pattern):
(function () {
function UserInfoLoader($q, facebookService, githubService) {
var _initPromise = null;
function initialization() {
var deferred = $q.defer(),
_initPromise = deferred.promise,
facebookLoading = facebookService.somePromiseFunc(),
githubLoading = githubService.somePromiseFunc();
$q.all([facebookLoading, githubLoading])
.then(function (results) {
// do something interesting with the results
deferred.resolve();
// set the promise back to null in case we need to call it again next time
_initPromise = null;
});
return promise;
}
this.initialize() {
// if there's already an initialization promise, return that
return _initPromise ? _initPromise : initialization();
}
}
angular.module('myApp').service('userInfoLoader', UserInfoLoader);
}());
This is great, because you can have multiple Controllers depend on the same workflow logic and they'll only produce one promise.
(function () {
function UserProfileController($scope, userInfoLoader) {
$scope.loading = true;
function load() {
userInfoLoader.initialize().then(function () {
$scope.loading = false;
});
}
load();
}
function UserMessagesController($scope, userInfoLoader) {
// same sort of loading thing
}
angular.module('myApp')
.controller('userProfileController', UserProfileController)
.controller('userMessagesController', UserMessagesController)
;
}());
To borrow from Mr. Osmani's book linked above, the loader service is like an air traffic controller. It coordinates the schedules of and passing information between multiple "airplanes", but they never have to talk to each other.
Another approach that I've seen is to use a FrontController, usually added on the body element, that manages a global loader, showing it during long-running async operations. That one's pretty simple, so I won't write it all out.
Do the fowllowing in each route:
$routeProvider.when("/your/path", {
templateUrl: "template/path",
controller: "controllerName",
resolve: {
getToken: ['TokenSvc',function (TokenSvc) {
return TokenSvc.getToken();
}]
}
});
You need that the getToken method return always the same object. Something like this:
obj.token = null;
obj.getToken = function(){
if(!obj.token){
var deferred = $q.defer();
obj.token = deferred;
deferred.promise.then(function(serverToken){
console.log("Got it. The token is ",serverToken);
}, function(status){
console.log("something is wrong ", status);
});
$http.get("url/to/token")
.success(function(data){
deferred.resolve(data);
})
.error(function(data, status){
deferred.reject(status);
});
}
return obj.token.promise;
}
I asked the wrong question yesterday (and got a goodanswer that worked), but am realizing it's not what I needed. I need to be able to retrieve JSON data (preferably once), store it, and access it throughout my service. The challenge I'm having is that all the examples I can find talk about using JSON and passing to the app/controller, whereas in this case I need to get it, check it, and then it dictates what my module/service does.
For instance, I have my App and Controller, and then I have a module such as (this is psuedo-code, not meant to run):
angular.module("myModule")
.service("myService1", function($q, myService2, $http) {
this.getModel = function() {
return {
title: "My Title",
desc: "My Desc"
options: function () {
if (condition A)
return "option1";
else
return "option2";
}
};
};
})
.service("myService2", function($q, $http) {
this.getCfgInfo = function () {
var defer = $q.defer();
$http.get("my/json/url").then(function(response) {
defer.resolve(response.data);
});
return defer.promise;
};
})
In this example, I'm wanting to get the JSON, and use it within myService1 for both literal values (title, desc) as well as for conditions (condition A within the if).
I know I can do something like this (thanks to Joel for helping yesterday):
service("myService1", function($q, myService2, $http) {
// get a promise object for the configuration info
var cfgProm = rtDataMapper.getCfgInfo()
this.getModel = function() {
return {
title: cfgProm.then(function(response) {
return response.JSON_NAME;
}),
and it works fine as I've got the title mapped back into my model and there is a watch(), but I'm stumped as to how I get, store, and use the JSON within the service itself as a conditional (i.e. if (condition A) where condition A is coming from the JSON. Trying to wrap these in .then() doesn't seem to make sense, or at least I can't figure out how to do it.
I'm new to Angular and am attempting to modify some code that was left to us. I'm guessing I don't need the myService2 just to get the JSON. Can anyone help point me in the right direction? I've spent several hours online but can't seem to find a relevant reference/example.
Thanks
Live demo (click).
I'm having the service immediately get the data when it is injected (that code will only run once no matter how many times you inject it). That's nice because you won't have to call a function to get the data - it's called for when creating the service.
Your service method that returns that data will need to return the promise of the data, of course, since you aren't guaranteed that it will have come through when you ask for it. You can pass arguments to that method to use to determine your conditions. All you need to do for that is use promise.then in the method and resolve the promise with the modified data. Since that method is returning the promise already, the modification will be updated on the resolve. See all of this below and in the demo.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, myService) {
myService.getData(15).then(function(data) {
$scope.myData = data;
});
});
app.factory('myService', function($q, $timeout) {
//this code only runs once when you first inject the service
//get data immediately
var deferred = $q.defer();
$timeout(function() { //simulate ajax call
var data = { //ajax response data
foo: 15,
bar: 'Some data!'
};
data = modifyData(data, 1);
deferred.resolve(data);
}, 500);
function modifyData(data, fooVal) {
if (data.foo === fooVal) {
data.baz = 'Conditional data!';
}
return data;
}
var myService = {
//data can be modified when it comes from the server,
//or any time you call this function
getData: function(fooVal) {
if (fooVal) { //if you want to modify the data
deferred.promise.then(function(data) {
data = modifyData(data, fooVal);
deferred.resolve(data);
});
}
return deferred.promise;
}
};
return myService;
});
I have a factory that returns an object from $http.get
app.factory( 'myFactory', function($http) {
return {
get: function() {
return $http.get('/data').success(function(data) {
return data
})
}
}
})
then
$scope.listings = myFactory.get()
In index.html, I use ng-repeat on listings.data and there is no problem finding each object.
Then from a directive I call .getListings() that's in my controller and in the Chrome Javascript console $scope.listings =
Object {then: function, success: function, error: function, $$v: Object}
Why can't I just use this?
$scope.listings.data
And is it ok to use this?
$scope.listings.$$v.data
What is $$v?
You are making little mistake in your code with get in service you return a promise object which will be filled when you sucessfully complete response from the server so kindly modify your code below to make it working.
app.factory( 'myFactory', function($http) {
return {
get: function() {
return $http.get('/data')
}
}
})
myFactory.get().then(function(data){
$scope.listings=data;
});