getAttribute return unresolved - angularjs

I'm just trying to save the attribute of an input value to a variable.
This is the code:
var sliderNumber = element.all(by.model('color.red')).get(1);
var firstNum = sliderNumber.getAttribute('value').then(function(value) {
return value;
});
//Some code that changes the sliderNumber attribute
expect(sliderNumber.getAttribute('value')).toEqual(firstNum + 1);
This gives me an error like this:
Expected '184' to equal Promise::433 ([[PromiseStatus]]: "pending")1.
I've also tried:
var firstNum = function() {
return sliderNumber.getAttribute('value').then(function(value) {
return value;
});
}
That didn't help at all. How do I resolve this promise?

Since .getAttribute() returns a promise, which will invoke your callback asynchronously, you need to put your test logic within the callback:
var sliderNumber = element.all(by.model('color.red')).get(1);
// get the initial value
sliderNumber.getAttribute('value').then(function(value) {
// once we've got the initial value, store it, then proceed with your test
var initialValue = parseInt(value, 10);
//Some code that changes the sliderNumber attribute
expect(sliderNumber.getAttribute('value')).toEqual((initialValue + 1).toString());
});
You can't simply get the return value outside of the callback, because that callback may or may not be called after the rest of your code.

Related

Angular JS object scope

I have written a simple Angular JS code which greets user depending on the time of the day. It works fine. The code is given below:
var modSvc = angular.module("appName",[]);
modSvc.provider("date",function(){
var greeting;
return {
showGreeting:function(value){
greeting = value;
},
$get:function(){
//it has to return an object which can have variables and functions
return {
showDate:function(){
var date = new Date();
return date.getHours();
},
showGreetingMessage:function(){
//var date = new Date();
return greeting + ", It's "+ this.showDate();
}
}
}
};
});
modSvc.config(function(dateProvider){
var hours = dateProvider.$get().showDate();
if(hours<12)
dateProvider.showGreeting("Good morning!");
else if(hours<17)
dateProvider.showGreeting("Good afternoon!");
else if(hours<22)
dateProvider.showGreeting("Good evening!");
else
dateProvider.showGreeting("Good night!");
});
function serviceController($scope,date){
$scope.greetingMessage = date.showGreetingMessage();
}
modSvc.controller("svcController",serviceController);
If you see showGreetingMessage function it has only one line of code which is:
return greeting + ", It's "+ this.showDate();
However showDate function resides at the same level as that of showGreetingMessage function. That's why this.showDate should not work and it should give error. But it works perfectly fine. How is it so?
It depends on the JavaScript engine that is used but according to the Mozilla reference your "this" actually references the parent object since you are returning an object.
As an object method
When a function is called as a method of an object, its this is set to the object the method is called on.
In the following example, when o.f() is invoked, inside the function this is bound to the o object.
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // logs 37

AsyncStorage.getItem returns undefined : React Native

Codeflow is-
I am checking if an entry called listobject exists in the AsyncStorage.
If it doesn't exist, then, I create an object, add few attributes and set the store. I get the store to obj as I have to compare in the next if condition.
If the listobject entry already exists(2nd time), then, it directly comes to the 2nd block, and compares. (The reason I get values to obj in 1st step is because I can have a common obj.data.isdirty condition.
Here is my code-
AsyncStorage.getItem('listobject').then((obj) => {
if(obj == undefined)
{
var obj1 ={};
obj1.data ={};
obj1.data.isdirty = true;
console.log("obj1 = "+ JSON.stringify(obj1));
AsyncStorage.setItem('listobject',obj1);
obj = AsyncStorage.getItem('listobject');
console.log("obj = "+ JSON.stringify(obj));
}
if(obj.data.isdirty)
{
obj.data.isdirty = false;
AsyncStorage.setItem('listobject',JSON.stringify(obj));
return AsyncStorage.getItem('listobject');
}
}).done();
I have 2 questions which are the outcome of the same issue-
Logs. I am setting obj1 and getting the same value for obj (so that I can compare the next if condition). Why am I not able to get the same value that I have set?
12-03 00:27:56.281 32598-487/com.abc D/ReactNativeJS: 'obj1 = {"data":{"isdirty":true}}'
12-03 00:27:56.286 32598-487/com.abc D/ReactNativeJS: 'obj = {"_37":0,"_12":null,"_59":[]}'
This is the end result of the above logs. I am getting that list.data.isdirty is undefined. I guess that because the JSON format I am accessing does not exist in obj i.e., obj.data.isdirty doesn't exist. So, how do I overcome this?
undefined is not an object (evaluating 'list.data.isdirty');
Please tell me what am I doing wrong?
I actually copied the object from one to another. It worked.
AsyncStorage.getItem('listobject').then((obj) => {
if(obj == undefined)
{
var obj1 ={};
obj1.data ={};
obj1.data.isdirty = true;
console.log("obj1 = "+ JSON.stringify(obj1));
AsyncStorage.setItem('listobject',obj1);
obj = obj1; //THIS IS WHAT I DID!
console.log("obj = "+ JSON.stringify(obj));
}
if(obj.data.isdirty)
{
obj.data.isdirty = false;
AsyncStorage.setItem('listobject',JSON.stringify(obj));
return AsyncStorage.getItem('listobject');
}
}).done();
I'm not quite following the entire question I do however see an issue with the use AsyncStorage. Going by the name, Async implies that the operations are asynchronous. So when you do getItem(key), you should either pass in a callback or use the Promise object it returns as you are doing in the first line of code.
obj = AsyncStorage.getItem('listobject');
console.log("obj = "+ JSON.stringify(obj));
obj is going to be the Promise in this case.
Then if you check on obj for the presence of a data and isDirty child property, they will not exist on the Promise.
Sometimes while doing console.log(AsyncStorage.getItem('Soomekey')) you will be getting undefined as you can't directly pull values from the AsyncStorage as returns a promise so what you should be writing is
const SomeFunction = async () => {
try {
const value = await AsyncStorage.getItem('somekey');
console.log(value);
} catch (err) {
console.log(err);
}
}

Cannot get iteration count of for loop cycle inside of the service result -> then

i have following method:
var i;
$scope.playAllSelectedSounds = function() {
try {
for( i; i < $scope.selectedSounds.length; i++) {
var fileName = $scope.selectedSounds[i].file;
var volume = $scope.selectedSounds[i].defaultVolume;
var filePath = "sounds/" +fileName+".mp3";
console.log(fileName);
MediaSrv.loadMedia(filePath).then(function(media){
console.log(media);
// !!!!!!!!!!! HERE I CANNOT GET value of the i VARIABLE
$scope.selectedSounds[i].state = 1;
// !!!!!!!!!!! HERE I CANNOT GET value of the i VARIABLE
$scope.selectedSounds[i].mediaInstance = media;
media.play();
media.setVolume(volume);
});
}
} catch(e) {
alert(JSON.stringify(e));
console.log(e);
$scope.showAlert("Error", "Error during the playing item");
}
};
Problem is that inside of the service:
MediaSrv.loadMedia(filePath).then(function(media){
I cannot get number o for cycle loop which i need to set in:
$scope.selectedSounds[i].state = 1;
Variable i is global i still cannot reach them. How can i solve it please?
It is not because i is not accessible, it is because i has run out of its limit because loadMedia is async and the value of i within the callback would become $scope.selectedSounds.length, since the for loop would have run out before the callback is invoked.
You could resolve this by using a closure variable representing the current item: You could just make use angular.forEach itself, and you don't event need to worry about accessing the right index. Instead just modify the object itself which is available as 1st argument of forEach evaluator function.
angular.forEach($scope.selectedSounds, function loadMedia(selectedSound, idx){
var fileName = selectedSound.file;
var volume = selectedSound.defaultVolume;
var filePath = "sounds/" +fileName+".mp3";
MediaSrv.loadMedia(filePath).then(function(media){
selectedSound.state = 1;
selectedSound.mediaInstance = media;
media.play();
media.setVolume(volume);
});
});
Also you forgot to initialize i in your case, which will cause your loop to not run at all.
Does it work if you create a local variable var that=i; just before your call to the promise, and then try to get "that" inside the promise return?
Otherwise try this :
for (var i in superarray){
(function(j) {
MyService.get(superarray[j].externalID).then(function(r) {
console.debug(j);
});
})(i);
}

Why do the private variables in a factory not get updated?

I have an interval in a factory that calls a function that fetches the latest exchange rates.
There will be some calculations that will need to be updated everytime the exchange rates are updated.
So I was just going to re-calculate the values everytime within $http.get.success.
However, the local variables don't seem to get updated. I created a simple jsfiddle to show you what I mean: http://jsfiddle.net/magician11/37msdsry/2/
app.factory('testFactory', function(){
var number1 = 0, number2 = 0;
var getLatestExchangeRates = function() {
$http.get('https://api.bitcoinaverage.com/ticker/global/IDR/')
.success(function(response) {
blockchainInfoExchangeRates.IDR = response.last;
});
printValues();
};
var printValues = function() {
console.log('number1: ' + number1);
console.log('number2: ' + number2);
};
$interval(getLatestExchangeRates, 60000);
getLatestExchangeRates();
Why doesn't number1 print out the updated value?
After returning from factory method, number1 property holds a value at the time the factory returned.
That is why number1 never get's updated.
To get access to the private variable, you need to return a function, which would capture a reference to original private variables, just like it already works with printValues function:
return {
getValues : function() { return {number1 : number1, number2: number2 }; }
printValues: printValues
};
This is how you can use it now:
console.log($scope.testFactory.getValues().number1);
$scope.currentNumbers = $scope.testFactory.getValues();
...
<p>{{currentNumbers.number1}}</p>

How to avoid Infinite $digest Loop error while working with ngResource

I am $watching the $scope.randomObjects in my directive. The $watch will throw an error if the function is not stable and I think that my curried function inside getDesiredAmountOfObjects is idempotent. Is here something going on with ngResource -objects that I can not see?
How can I fix this? Also the desiredAmount is fixed for now.
Here is snippet from my controller:
..
var getDesiredAmountOfObjects = function (objects, randomObjects) {
return function (desiredAmount) {
var amount = desiredAmount || 1;
if (amount >= objects.length) {
return objects;
}
var randoms = randomObjects.slice(0, amount);
//logged objects are always the same in each $digest loop.
//including the $$hashKey
console.log(random);
return randoms;
};
};
//this will initialized only once in controller
ObjectRes.query(function(data) {
$scope.objects = data;
var randomObjects = [];
angular.extend(randomObjects, data);
randomObjects.sort(function () {
return 0.5 - Math.random();
});
$scope.randomObjects = getDesiredAmountOfObjects($scope.objects, randomObjects);
});
..
I can't see everything because I haven't seen how the $watch and views are set up, but something jumps out at me.
If randomObjects is being called from within a watcher, and set to a value on the scope which is also watched, it will cause an infinite $digest cycle.
This is because you are constantly returning a new array reference (slice returns a new array). The watcher of the result will recognize that the reference changed, which will require a new loop of the digest, which will ask for new randomObjects which will trigger that something changed, etc.
Usually, you fix this by making sure your function returns references to the same object, and does not create new arrays. In your case, you are calling slice which creates a new array every time. You need to make sure this function returns the same array every time.
Something like this, perhaps?
var getDesiredAmountOfObjects = function (objects, randomObjects) {
var result = [];
return function (desiredAmount) {
var amount = desiredAmount || 1;
if (amount >= objects.length) {
return objects;
}
// clear the result array and put randoms into it
result.length = 0;
result.push.apply(result, randomObjects.slice(0, amount));
//logged objects are always the same in each $digest loop.
//including the $$hashKey
console.log(result);
return result;
};
};

Resources