Getting data from Angular Promise - javascript

I am trying to get the response of MotorRestangular.all('Motors').getList() assigned to the variable a so I can use it later. The problem is that if I try to access a inside my return function it is undefined. I know that this isn't the correct way to accomplish what I need but I have no clue how do to it any other way.
myApp.factory('Configurations', function(Restangular, MotorRestangular) {
var a;
var Motors = function() {
MotorRestangular.all('Motors').getList().then(function(Motors){
a = Motors;
});
}
return {
config: function(){
Motors();
console.log(a);
var g = _.groupBy(Motors, 'configuration');
console.log(g);
var mapped = _.map(g, function(m) {
return {
id: m[0].configuration,
configuration: m[0].configuration,
sizes: _.map(m, function(a) {return a.sizeMm})
}});
}
}
});

Please don't use deferred objects. If what you had in your answer worked - then this will work too:
myApp.factory('Configurations', function (Restangular, MotorRestangular, $q) {
var getConfigurations = function () {
return MotorRestangular.all('Motors').getList().then(function (Motors) {
//Group by Cofig
var g = _.groupBy(Motors, 'configuration');
//Map values
return _.map(g, function (m) {
return {
id: m[0].configuration,
configuration: m[0].configuration,
sizes: _.map(m, function (a) {
return a.sizeMm
})
}
});
});
};
return {
config: getConfigurations()
}
});
Additionally if an error happens, the returned promise is not left pending forever.

I just solved this. What was happening is that config: was returning before a was filled. The code below works.
myApp.factory('Configurations', function(Restangular, MotorRestangular, $q) {
var getConfigurations = function(){
var deferred = $q.defer();
MotorRestangular.all('Motors').getList().then(function(Motors){
//Group by Cofig
var g = _.groupBy(Motors, 'configuration');
//Map values
var mapped = _.map(g, function(m) {
return {
id: m[0].configuration,
configuration: m[0].configuration,
sizes: _.map(m, function(a) {return a.sizeMm})
}});
deferred.resolve(mapped);
});
return deferred.promise;
};
return {
config: getConfigurations()
}
});

Related

Error in Returning Promise ,Getting Error as .then is not a function in Angular JS

I am getting the error as modifyProduct.then is not a function, I have read through some article and it says because I have not returned any promises, How I can achieve this, Can someone help me
Here I am calling modifyProduct inside executionFromCompany function and then I am using executionFromCompany inside the controller
var app = angular.module('myApp', ["chart.js"]);
app.factory('ProductsService', function($http) {
function getProduct() {
return $http.get('finalmsodetails.json').then(function(response) {
//console.log(response.data);
return response.data;
});
}
function modifyProduct() {
return getProduct().then(function(rawData) {
newtest = rawData;
//console.log('test', newtest.length);
var lightData = rawData.map(function(item) {
// use Object.assign to prevent mutating original object
var newItem = Object.assign({}, item);
var lightExecutions = item.executions.map(function(d) {
var ld = {
id: d.id,
orderId: d.orderId,
executionStatus: d.executionStatus,
executedOn: d.executedOn,
executedBy: d.executedBy,
executedByDisplay: d.executedByDisplay,
};
return ld;
});
newItem.executions = lightExecutions;
return newItem;
});
return lightData;
});
}
function executionFromCompany() {
return modifyProduct.then(function(lightData) {
executionByCompany = $filter('filter')(lightData.executions, function(inputs) {
if ((inputs.executedBy == 'a')) return inputs;
});
console.log(executionByCompany);
return executionByCompany;
});
}
return {
getProduct: getProduct,
modifyProduct: modifyProduct,
executionFromCompany: executionFromCompany
};
});
app.controller('MainCtrl', function($scope, ProductsService) {
ProductsService.executionFromCompany().then(function(value) {
console.log(value);
}, function(err) {
// Here will be if there was an error
})
});
modifyProduct is a function, not an object
change this
modifyProduct.then
to this
modifyProduct().then

how nicely solve selenium promise? protractor

I wrote the following code (page object pattern). Works correctly.
However, I don't like this, because I can't remove "then" from "pressHelpLink". Instead add the code in getElementByLink.
I would like to see ElementFinder Promise (instead of ManagedPromise) as result of getElementByLink("Help")
How nicely solve selenium promise?
var self = Page.create({
url: {value: ''},
// function:
getElementByLink: {
value: function (link) {
return element.all(by.repeater('items')).then(function (el) {
var my_array = el.map(function (el) {
return el.element(self.by.xpath('a'));
});
var element_array_finder = protractor.ElementArrayFinder.fromArray(my_array);
var element = element_array_finder.filter(function (el) {
return el.getText().then(function (text) {
return text === link;
})
});
return element;
}).then(function (element) {
world.expect(element.length).equal(1);
return element[0];
});
}
},
// elements:
HelpLink: {
get: function () {
return self.getElementByLink('Help');
}
},
// method:
pressHelpLink: {
value: function () {
return self.HelpLink.then(function (el) {
return el.click()
});
}
},
});
Why not use cssContainingText? Maybe something like...
// elements:
HelpLink: {
get: function () {
return element(by.cssContainingText('a', 'Help');
}
},
// method:
pressHelpLink: {
value: function () {
return self.HelpLink.click()
}
},

Angularjs retain local variable

I have a factory like this:
TestFactory= function () {
var objectName=null;
return {
SetName:function(name) {
objectName = name;
},
GetName:function() {
return objectName;
},
Init:function() {
return angular.copy(this);
}
}
}
A controller like:
TestController = function($scope) {
$scope.TestClick = function () {
var tstA = TestFactory.Init();
var tstB = TestFactory.Init();
tstA.SetName('test A')
tstB.SetName('test B')
console.log('A', tstA.GetName());
console.log('B', tstB.GetName());
}
}
In the console I get Test B for both objects.
How can I make a proper instance of this object?
I would like to use the objectName value in other functions of the factory.
Take into account that in Angular, Factories are singletons, so the instance is always the same.
You can do the following:
TestFactory= function () {
var objectName={};
return {
SetName:function(property,name) {
objectName[property] = name;
},
GetName:function(property) {
return objectName[property];
},
Clear:function(property) {
delete objectName[property]
}
}
}
Then in your controller:
TestController = function($scope, TestFactory) {
$scope.TestClick = function () {
TestFactory.SetName('a','test A')
TestFactory.SetName('b','test B')
console.log('A', TestFactory.GetName('a')); // test A
console.log('B', TestFactory.GetName('b')); // test B
}
}
Couple of issues. First your returning an object rather than a function from your factory.
app.factory('TestFactory', function() {
return function() {
var objectName = null;
var setName = function(name) {
objectName = name;
};
var getName = function() {
return objectName;
};
return {
SetName: setName,
GetName: getName
};
};
});
Then you can just instantiate like this:
var tstA = new TestFactory();
var tstB = new TestFactory();
Services and factories are singletons so I think you can achieve what you want with a more appropriate use of the factory by providing an Init function that returns the common code and unique name like so:
angular.module('app')
.factory('ServiceFactory', serviceFactory);
function serviceFactory() {
return {
Init: function (name) {
return {
objectName: name,
setName: function (name) {
this.objectName = name;
},
getName: function () {
return this.objectName;
}
};
}
};
}
This leaves the possibility to use it as a factory that can initialize many types.
You basically need to create a simple getter/setter.
angular.module('app', [])
.controller('TestController', testController)
.service('serviceFactory', serviceFactory);
testController.$inject = ['serviceFactory'];
function testController(serviceFactory) {
serviceFactory.set('A', {
name: 'test A'
});
serviceFactory.set('B', {
name: 'test B'
});
console.log(serviceFactory.getAll());
console.log(serviceFactory.get('A'));
console.log(serviceFactory.get('B'));
}
function serviceFactory() {
var
_model = {
name: ""
},
_data = {};
return {
set: function(key, data) {
_data[key] = angular.extend({}, _model, data);
},
get: function(key) {
return _data[key];
},
getAll: function() {
return _data;
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<body ng-app="app" ng-controller="testController"></body>

Unit testing an AngularJS service with angular-translate calls

I've tried numerous different ways of writing a unit test for an AngularJS service that calls angular-translate, and I just can't get it to work out. Any advice would be appreciated. Here's my most promising example:
(function() {
var app = angular.module("theApp", ["pascalprecht.translate"]);
var theService = function($translate) {
var theFunction = function(data) {
return $translate("FOO", { input: data.in }).then(function(trans) {
data.out = trans;
});
};
return {
theFunction: theFunction
};
};
app.factory("theService", ["$translate", theService]);
}());
describe("theService", function() {
beforeEach(module("theApp", function($translateProvider, $provide) {
$translateProvider.useLoader('customLoader');
$provide.service('customLoader', function($q) {
return function() {
var deferred = $q.defer();
deferred.resolve({
"FOO": "foo {{input}}"
});
return deferred.promise;
};
});
}));
it("function translates input", inject(function($rootScope, theService) {
var data = { in: "bar", out: "fail" };
theService.theFunction(data);
$rootScope.$apply();
expect(data.out).toBe("foo bar");
}));
});
A JSFiddle can be found here: http://jsfiddle.net/danBhentschel/q71r874t/
Okay. I guess I figured it out on my own. I started out with the test found here:
https://github.com/angular-translate/angular-translate/blob/master/test/unit/service/translate.spec.js#L409
And I was able to slowly morph this passing test into what I wanted to do:
(function() {
var app = angular.module("theApp", ["pascalprecht.translate"]);
var theService = function($translate) {
var theFunction = function(data) {
return $translate("FOO", { input: data.in }).then(function(trans) {
data.out = trans;
});
};
return {
theFunction: theFunction
};
};
app.factory("theService", ["$translate", theService]);
}());
describe("theService", function() {
var $rootScope;
beforeEach(module("theApp", function($translateProvider, $provide) {
$translateProvider.useLoader("customLoader");
$provide.service("customLoader", function($q) {
return function() {
var deferred = $q.defer();
deferred.resolve({
"FOO": "foo {{input}}"
});
return deferred.promise;
};
});
}));
beforeEach(inject(function ($translate, _$rootScope_) {
$rootScope = _$rootScope_;
$translate.use("en_US");
$rootScope.$apply();
}));
it("function translates input", inject(function(theService) {
var data = { in: "bar", out: "fail" };
theService.theFunction(data);
$rootScope.$apply();
expect(data.out).toBe("foo bar");
}));
});
A JSFiddle with the solution can be found here: http://jsfiddle.net/danBhentschel/yLt3so14/
Please feel free to point out any stupid mistakes I made. I'm still kinda new at this.

AngularJS $q.all & multiple $q.defer

Even though I have managed to make my code work, there is something I don't understand. The following piece of code functions correctly:
socket.on('method', function() {
var payload = {
countrycode: '',
device: ''
};
var d1 = $q.defer();
var d2 = $q.defer();
$q.all([
geolocation.getLocation().then(function(position) {
geolocation.getCountryCode(position).then(function(countryCode){
payload.countrycode = countryCode;
d1.resolve(countryCode);
});
return d1.promise;
}),
useragent.getUserAgent().then(function(ua) {
useragent.getIcon(ua).then(function(device) {
payload.device = device;
d2.resolve(device);
});
return d2.promise
})
]).then(function(data){
console.log(data); //displays ['value1', 'value2']
})
});
Is there a better way of achieving this? Before I had only one deferred variable, i.e. varvar deferred = $q.defer(); but that way the .then() function returned an object with double the results.
So the few question I have are:
Do I need multiple $q.defer vars?
Is the above the best way to wait for two async calls to finish and populate the payload object?
socket.on('method', function() {
var payload = {
countrycode: '',
device: ''
};
geolocation.getLocation()
.then(function(position) {
return geolocation.getCountryCode(position);
})
.then(function(countryCode) {
payload.countrycode = countryCode;
return useragent.getUserAgent();
})
.then(function(ua) {
return useragent.getIcon(ua);
})
.then(function(device) {
payload.device = device;
console.log(data); //displays ['value1', 'value2']
});
});
read the promise chaining part
You could always separate your code into smaller semantic blocks like so:
getCountryCode = function() {
var d = $q.defer();
geolocation.getLocation()
.then(function(position) {
return geolocation.getCountryCode(position)
})
.then(function(countryCode) {
d.resolve(countryCode);
})
.fail(function(err) {
d.reject(err);
})
return d.promise;
};
getDevice = function() {
var d = $q.defer();
useragent.getUserAgent()
.then(function(ua) {
return useragent.getIcon(ua)
})
.then(function(device) {
d.resolve(device);
})
.fail(function(err) {
d.reject(err);
});
return d.promise;
}
That will shorten your actual parallel call ($q.all) quite a bit:
socket.on('method', function() {
$q.all([getCountryCode(), getDevice()])
.spread(function(countryCode, device) {
var payload = {
countryCode: countryCode,
device: device
};
// ... do something with that payload ...
});
});
To synchronize multiple asynchronous functions and avoid Javascript callback hell:
http://fdietz.github.io/recipes-with-angular-js/consuming-external-services/deferred-and-promise.html

Categories