save an attribute value to a variable - angularjs

I need to save an attribute value to a variable to be sent to a later object to verify a picture I upload which gets a unique src id is accessible using the src attribute I obtain. Later a search through a list of pictures will be done to find that particular uploaded picture.
getPictureSrc: function() {
var el = $('img');
var uniqueId = el.getAttribute('src');
return uniqueId;
},
findPicture: function() {
browser.get('a different webpage then the upload page');
var findPic = getPictureSrc();
var allPics = $$('img');
helper.expectedConditions.isVisible(allPics.$(findPics));
},
However when I run this code, I do a console.log() and it throws back the list of available commands. Not the source. However if I do an expect against some random value the src does show. So I guess there are two questions, how do I print an attribute value to console and how do I pass an attribute value from object to object. Thank you.

However when I run this code, I do a console.log() and it throws back the list of available commands.
getPictureSrc() returns a promise. A promise is what you see printed on the console. If you need the actual value, resolve the promise explicitly:
getPictureSrc().then(function (src) {
console.log(src);
});
However if I do an expect against some random value the src does show.
This is the magic of the expect() - it is patched (by jasminewd package) to implicitly resolve promises before making an expectation. Having expect() accepting promises is quite convenient.

Related

Why/how do the elements of this array change between the console.log calls?

I have an anuglarJS controller that calls an API via a service to return data. Ths issue is that sometimes, the data is not being updated in a directive that uses the data that is returned.
However, digging into this resulted in observing some very strange behavior. I added several console logs to debug what was happening, and discovered that the number of items in a property on the array is changing from one console call to the next.
The controller code is as follows:
init(){
this.ftService.getSitePromise(true).then((result: ng.IHttpPromiseCallbackArg<Site>) => {
let ctrl = this;
ctrl.isLoadingItems = true;
ctrl.hideSplash = true;
ctrl.siteReady = true;
ctrl.curSite = result.data;
ctrl.curSite.Items = [];
console.log("end of header site call");
ctrl.$timeout(function () {
console.log(ctrl.curSite.Items);
console.log("start get site items first call")
ctrl.ftService.getSitePromise(false).then((result: ng.IHttpPromiseCallbackArg<Site>) => {
console.log("return first call result.data.Items: " + result.data.Items.length);
ctrl.curSite.Items = result.data.Items;
ctrl.isLoadingItems = false;
console.log("return first call ctrl.curSite.Items: " + ctrl.curSite.Items.length);
console.log(ctrl);
console.log(ctrl.curSite);
console.log(ctrl.curSite.Items);
});
}, 200);
});
}
The console from this code executing, when the data isn't being shown as expected is as follows:
Any insight as to how this is occurring, and/or how I might correct it, would be greatly appreciated.
Edit: I didn't read the comments before posting. I didn't see your problem was solved. Hopefully this may help someone else in the future??
Why/how do the elements of this array change between the console.log calls?
Objects can change in console.log calls because the deeper nested properties are accessed lazily meaning that the console will only grab them when you click the little arrow to expand the object or if they are a shallow property.
You can change this behavior by cloning the object using Object.assign though you may need to clone the object deeply (which Object.assign({}, myObj) does not.
The stackoverflow snippet console won't show the correct results. Open your chrome dev tools to see the real result.
// OPEN THE DEVELOPER TOOLS CONSOLE
let myObj = {
shallowProp: 'some value',
arr: ['initial value']
};
// notice that when this logs, it seems like the change to myObj happens before the log but it does not
console.log(
'myObj initial log',
myObj
);
// using `Object.assign` clones the object so that when expanded in the console, the value is the initial value
console.log(
'myObj initial log with Object.assign',
Object.assign({}, myObj)
);
// when the value is actually changed
myObj.arr = ['new value'];
// the final state
console.log('myObj after change', myObj);
Conclusion: try cloning your object before logging it the console.

How to loop through $resource returned query and get desired value?

I am using MEANJS
In my controller i have
// Find a list of Cars
$scope.findHome = function() {
$scope.cars = Cars.query();
console.log($scope.cars);
};
Which outputs
here i want to get the _id string inside the first array 0: Resource
I tried $scope.cars[0]._id which returns undefined, Please help.
You are inspecting the results of the query immediately after the call, but ngResource is asynchronous, so perhaps the data has not yet returned from the server by the time you are trying to access it. Try putting your access in the callback function passed to query().
$scope.cars = Cars.query(function() {
console.log($scope.cars);
console.log($scope.cars[0]._id);
});

Trying to get ng-csv to work with Firebase

I have data stored on Firebase. I have a function that will grab the information from Firebase and return it as an array. I want to be able to use ng-csv to download that file as a .csv however when I download it is an empty file.
Is it possible to use ng-csv if I am trying to grab data from Firebase and if so does anyone have any examples?
Update (from OPs duplicate question):
I am trying to use ng-csv to allow a user to download a .csv file by clicking a button. The information is stored in Firebase and I have created a function that returns the needed information from Firebase as an array. However, I think the problem is when the button is clicked the file is downloaded before the information is pulled from Firebase and loaded, so the .csv file is always empty. Is there a way around this? Here is my code in my main.js app:
this.export = function() {
var results = fireFactory.getResults() //code that returns the array of objects
results.$loaded().then(function(array) {
var test= [];
test.push(array[0]);
test.push(array[1]);
return test;
};
};
Here is my code in my HTML file:
<button class ="btn" ng-csv="main.export()" filename="test.csv">Export</button>
Is there anyway to delay the file downloading until the information has been loaded and returned from the main.export() function?
You are almost there. Frank van Puffelen was on the right path, but stopped short of providing the fix for your code.
return test;
the above statement inside your callback is returning the result inside a promise. This results can only be consumed using promise aware code. Fortunately, ng-csv accepts a promise. If the promise is returned it should work:
this.export = function() {
var results = fireFactory.getResults()
//Here we return the promise for consumption by ng-csv
return results.$loaded().then(function(array) {
var test= [];
test.push(array[0]);
test.push(array[1]);
//the array is returned from the callback, not export
return test;
};
};
You're being tricked by the asynchronous nature in which Firebase loads data. You seem to be thinking that return test; in your original code returns a value from the export function. But if you look more carefully you'll notice that you're actually returning from the (anonymous) callback function.
It's a bit easier to see this, if we separate the callback function out and add some logging statements:
function onDataLoaded(array) {
console.log('Got results from Firebase');
var test= [];
test.push(array[0]);
test.push(array[1]);
return test;
};
this.export = function() {
console.log('Starting to get results from Firebase');
var results = fireFactory.getResults() //code that returns the array of objects
console.log('Started to get results from Firebase');
results.$loaded().then(onDataLoaded);
console.log('Registered result handler');
};
When you call fireFactory.getResults() Firebase will start downloading the data from its servers. Since this may take some time, the downloading happens asynchronously and the browser continues executing your export function, which registers a callback that you want invoked when the data from Firebase is available.
So you'll see the following output in the JavaScript console:
Starting to get results from Firebase
Started to get results from Firebase
Registered result handler
Got results from Firebase

How to mock get(id) requests

I am building an application prototype and try to mock the REST web-services.
Here is my code:
var mock = angular.module('mock', ['ngMockE2E']);
mock.run(function($httpBackend){
users = [{id:1,name:'John'},{id:2,name:'Jack'}];
$httpBackend.whenGET('/users').respond(users);
$httpBackend.whenGET(new RegExp('\\/users\\/[0-9]+')).respond(users[0]);
}
Everything is ok, my resource User.query() returns all users, and User.get({id:1}) and User.get({id:2}) returns the same user (John).
Now to improve my prototype, I would like to return the appropriate user, matching the good id.
I read in the angular documentation I should be able to replace the RegExp URI by a function. The idea is to extract the id from the url to use it in respond method.
I then tried this:
$httpBackend.whenGET(new function(url){
alert(url);
var regexp = new RegExp('\\/users\\/([0-9]+)');
id = url.match(regexp)[1];
return regexp.test(url);
}).respond(users[id]);
The problem is the url parameter is always undefined. Any idea to achieve my goal?
By using new function(url) your app tries to instantiate a new object from your anonymous function and pass that new object as the first argument of the $httpBackend.whenGET() call.
Of course, at the time of calling whenGET() no URL is provided, thus it is always undefined.
You should pass the function itself (and not an object instanciated using the function). E.g.:
$httpBackend.whenGET(function (url) {
...
}).respond(users[id]);
UPDATE:
After some more digging it turned out that the option to pass a function as the first argument to whenGET was added in version 1.3.0-beta.3. The docs you were reading probably referred to the latest beta version, while you were using an earlier version.
(Note that even versions 1.3.0-beta.1 and 2 did not provide this option.)
Without getting into much detail, responsible for verifying a matching URL is MockHttpExpectation's matchUrl method:
function MockHttpExpectation(method, url, data, headers) {
...
this.matchUrl = function(u) {
if (!url) return true;
if (angular.isFunction(url.test)) return url.test(u);
if (angular.isFunction(url)) return url(u); // <<<<< this line does the trick
return url == u;
};
The line if (angular.isFunction(url)) return url(u); is the one that gives the option to directly pass a function and was added in version 1.3.0-beta.3 (as already mentioned).
But, if you still want to pass a function to a previous AngularJS version, you could "trick" angular into believing you passed a RegExp, by providing an object with a test method.
I.e. replace:
.whenGET(function (url) {...})
with:
.whenGET({test: function (url) {...}})
See, also, this short demo.
I found a solution by using a function in the respond part instead of the when part:
$httpBackend.whenGET(new RegExp('\\/users\\/[0-9]+')).respond(
function(method, url){
var regexp = new RegExp('\\/users\\/([0-9]+)');
var mockId = url.match(regexp)[1];
return [200, users[mockId]];
}
});

Calling Service's method multiple times holds single data instance

I am using services for my AngularJS project and trying to call a service.method using a for loop, like this :
for( key in URLs) {
Service.fetchXML(key);
}
Service description:
[..]
fetchXML : function(resource) {
var prop = SomeVar[resource]; //SomeVar is declared within the service
$.get('xmlURL.xml?resource='+prop, function(data) {
//adds data to the IndexedDB after properly parsing it.
console.log(resource)
dbAdd();
})
Problem is when I try resource inside fetchXML() method; its set permanently, means if the loop runs for five times, only one instance of fetchXML() is created and console.log(resource) returns the same for all five iterations.
Please tell me what am I doing wrong here.
for( key in URLs) {
Service.fetchXML();
}
Should be passing parameter to function since it is used as resource to create prop.
for( key in URLs) {
Service.fetchXML(key);
}
This should have been fairly easy to troubleshoot. First it would be apparent in the request url inspected in browser console/dev tools.
Also using some simple degugger or console.log() statements in function would have helped. Or setting breakpoint on the function and stepping through it to see variable values

Resources