javascript object to string issue - javascript

I am using this code (from Harsha Jagadish) that does a quick little speed test to my URL of choice. It outputs the expected result just fine
return this.each(function() {
var g = foo();
$(this).text(g).append("Mb per second" + newg);
});
But what I need to do is grab that same output to compare if it's greater or less than a specific number. The issue is it's an object. I tried JSON.stringify and a couple of things, but no luck.
What am i missing?

Related

Var returning 'undefined' ASP.net mvc

I didn't want to use the default site.js, but just write the Javascript on the view page itself, "its kinda confusing for me". but still, after further exploration online, I still cannot figure out why I am not redirected as intended. I tried running codes from https://www.dreamincode.net/forums/topic/414946-pick-website-from-random-list-redirect/
and How do I make a HTML button open in random links in new tab
in which both seemed to work in online simulator, w3school. But when I replicated the functions, it seemed to return a null/undefined value for redirection.
Code:
var Links = ['https://longdogechallenge.com/ ',
'http://heeeeeeeey.com/ ',
'http://corndog.io/ ',
'https://thezen.zone/ ',
'http://hasthelargehadroncolliderdestroyedtheworldyet.com/ ',
// lots more snipped
'http://papertoilet.com/ '];
var RandFx = Links[Math.floor(Math.random * Links.length)];
function RandX() {
window.location = RandFx;
}
As stated, the RandFx seems to be containing undefined value. What am I doing incorrectly? can it be due to the extended length of urls in the Links variable?
Math.random is a function, you should be using Math.random() to get the actual result:
var RandFx = Links[Math.floor(Math.random() * Links.length)];
The problem is that the index you are calculating results in NaN:
var index = Math.floor(Math.random * Links.length)
var RandFx = Links[index];
And Links[NaN] is undefined.
The index is NaN because you are calling Math.random instead of Math.random(). Passing the function instead of the result of the function gives you an error.
This jsfiddle shows what's happening: https://jsfiddle.net/74skonhL/

Format numbers to integers with SI prefix

I am drawing a chart, which gets dollar values (from 0 to millions), and I am trying to show nice ticks. I already used d3.nice to get 5 ticks that all have nice values, it's very cool. But since there's such a large variance, I am struggling to display my dollar values correctly.
I wish to do:
0-999: shows itself
1,000 - 999,999: shows 1k-999k (it's ok if 999,500 shows 1M, but not ok to show 1.00k by using d3.format('.3s'), or having 467k go to 400k by using d3.format('.1s'))
1,000,000 - 999,999,999: shows 1M-999M (also ok if it rolls over when rounding)
Prior to d3 version 4, this was easy. You could do:
.ticks((d) => {
var prefix = d3.formatPrefix(d);
return prefix(d).toFixed()+''+prefix.symbol;
})
But now, I am reading the d3 v4 docs after this fails on me, and it says:
The d3.formatPrefix method has been changed. Rather than returning an SI-prefix string, it returns an SI-prefix format function for a given specifier and reference value. For example, to format thousands:
var f = d3.formatPrefix(",.0", 1e3);
f(1e3); // "1k"
f(1e4); // "10k"
f(1e5); // "100k"
f(1e6); // "1,000k"
This seems impossible to accomplish now, then, because I want to vary the amount of significant digits, but I see no obvious way to accomplish that. Am I missing something simple?
If I understand your desired output correctly, you can use the number itself to define the value of d3.formatPrefix.
Look at this demo:
[1, 999, 1000, 999000, 1000000].forEach(function(d) {
var prefix = d3.formatPrefix(".0", d)
console.log(d + ": " + prefix(d))
})
<script src="https://d3js.org/d3.v4.min.js"></script>
PS: Using this approach, 999500 will give you 1000k, not 1M.
Okay well I suppose this was easy enough, but a little hacky. Here's the formatter function I used to make this behaviour:
(val) => {
let prefix = d3.formatPrefix('.3s', val);
let str = prefix(val);
if (val === 0) {
return '0';
}
return parseInt(str.slice(0, str.length - 2))+''+str.slice(str.length - 1);
}
I would be happy to use something better so if you have a cleaner answer, post and I'll accept.

Can't assign querySelectorAll() to a variable - weird behaviour

I was trying to crawl a very old website for a specific tag, I need to get it by it's for= attribute. So I used this piece of code.
var character = document.querySelectorAll("label[for=char_1]");
For some reason it returns an undefined, but I was using this script for a few days now and it worked like a charm. Here's the fun part. Typing that command in browsers console will result in undefined. But typing this alone:
document.querySelectorAll("label[for=char_1]");
Will return a proper NodeList. Why it won't assign to a variable...?
edit: It seems that deleting var and typing character without it will make it work. It's resolved but I would still love to get an answer to "why is this happening"?
edit2:
for (var i = 0; i < 15; i++) {
var character = document.querySelectorAll("label[for=char_" + i +"]");
console.log(character); // this will return [] from the script.
var color = character[0].children[0].style.color;
}
A simple for loop. All I get is Cannot read property 'children' of undefined. But I can type in the very same command document.querySelectorAll... and it will work in the browser and will return NodeList.
I had it working like this in a very hacky script. It worked.
var character1 = document.querySelectorAll("label[for=char_1]");
var characterColor1 = character1[0].children[0].style.color;
edit3:
var character1 = document.querySelectorAll("label[for=char_1]");
var characterColor1 = character1[0].children[0].style.color;
var character2 = document.querySelectorAll("label[for=char_2]");
var characterColor2 = character2[0].children[0].style.color;
// ...
The above code works without a single problem though. I don't think it's DOM not being ready as this code is also run from Greasemonkey script and it works. The only difference is the for loop.
var x = ""; // returns undefined, because it's a var assignment.
var elements = document.querySelectorAll('div');
That's expected behavior when pasted into the console.
edit: It seems that deleting var and typing character without it will make it work. It's resolved
I'm afraid you're creating a global scope variable now. or perhaps characters is an already defined variable in that scope.
Buhah, as I said in edit 3 "the only difference is the for loop". I was so busy trying to find an answer in the DOM-related things that I made the simplest mistake ever done in programming.
See?
char_1
With...
for(var i = 0...)
0! And I was testing char_1 in the browser instead of char_0. Which - truly - returns [] instead of something useful. Time to go on a holiday break I guess, my brain seems to be there already. :)

update html according to json

I have a JSON script which contain live matches. These changes every 5 minutes. The changes could for instance be the keys live_in or score. Beside this matches are also deleted and added to the JSON. I want to keep my html output updated at all time how can i do this the best possible way? So far i've set the updating speed to 5 seconds for testing purposes. I've tried so far to set the divs id to equal to the match_id and thereby update by
$('div#match-date-id-' + match['match_id']).html('test');
However does not seem to update. How can i do this the best possible way? i've created a plnkr which enable you to download it with a json snippet, which can be edited in order to check.
plnkr.co/edit/eQCShhW01OG5jU4VLx04?p=preview
My bad earlier on :-) Now I've done more thorough testing and updated the plunker code. What I found in the test: the filter was trying to use an undefined value (match.id), also the filter was trying to compare values from different datatypes (String vs. Integer); so it wasn't working as intended:
Original:
match = match.filter(
function(match) {
return match.id > lastId;
});
Corrected code:
match = match.filter(
function(match) {
return parseInt(match.match_id) > lastId;
});
Above match_id represents String datatype in your JSON file, so I had to convert it to Integer before comparison. More info about JSON data-types. Following the older filter functionality, no match passed the comparison test.
Also for testing purposes I commented out the following line:
if (match.match_id > lastLoadedMatch) {
//lastLoadedMatch = match.match_id
}
because in the second round of updates with the same testing data, no data passes that condition.
Also, I think you need to convert match_id to Integer as well; like following:
var matchId = parseInt(match.match_id)
if ( matchId > lastLoadedMatch) {
lastLoadedMatch = match.match_id
}
I hope you find it useful :-) + note I added a timestamp for those updates; so it's clearly visible that the updates take place now every 5 seconds.

Why is the .text() function returning [object Object] in ngScenario for AngularJS e2e?

Update: A Solution below!
I'm fairly new to website development but I've been tasked with developing e2e (end-to-end) tests for a developing website that uses AngularJS. As a result I've been looking down the road of using AngularJS's karma-run ngScenario testing wrapper.
Anyway, just getting started I want to make sure that a simple hyperlink's text matches part of its href address. There isn't need to know the structure of this code snippet, but these are thumbnails for user profiles, and you can click the thumbnail object completely (the first 'a') or you can click a link displaying their name (the second 'a').
There dozens of these on a page.
Here is what a part of the page looks like loaded with a user "PurplePenguin".
<div class="thumbnail__section">
<a href="/profile/PurplePenguin">
<div class="thumbnail__bottom">
<div class="thumbnail__rating ng-binding"> </div>
<div class="thumbnail__info">
<div class="thumbnail__name">
<a class="ng-binding" href="/profile/PurplePenguin">PurplePenguin</a>
</div>
[...]
Essentially I want a test that will take the text of the second 'a' element and check it against the href attribute: "assert that href '/profile/PurplePenguin' equals '/profile/' + 'PurplePenguin'"
This is what I've made just wanting to test the first thumbnail's 'a', (in my time writing "PurplePengiun" is the first user every time so I could hard code it).
it('should have the performer\'s name match the link', function() {
// "eq(n)" gets the nth instance of the element;
// "> a:eq(0)" grabs its first child a
var nameElement = element('.thumbnail__name:eq(0) > a:eq(0)');
// These work and pass
expect(nameElement.text()).toBe('PurplePenguin');
expect(nameElement.attr('href')).toBe('/profile/PurplePenguin');
// This does not
var textString = nameElement.text(); // textString == "[object Object]"
expect(nameElement.attr('href')).toBe('/profile/' + textString);
This gets returned:
expect element '.thumbnail__name:eq(0) > a:eq(0)' get attr 'href' toEqual "/profile/[object Object]"
expected "/profile/[object Object]" but was "/profile/PurplePenguin"
So I've figured out how to find the particular element on the page I need, but trying to manipulate the text of a simple 'a' element only gives me [object Object].
Some things I've tried with my basic knowledge of JS:
nameElement.text().toString(), nameElement.text().value(), nameElement[0].text()
Trying things other than text()
nameElement.html() and nameElement.val()
They too return [object Object] when trying to use them as strings.
It seems that looking at the values and attributes of these elements only works when using the very specific API functions like .toBe or .toEqual, but I want to assert that a specifically formatted string is made.
Thank you for any help!
Solution
Thanks for that bit of insight Andyrooger, I had actually taken a stab at the query function before posting my question but gave up on it too quick. Your explanation gave me the idea to start looking deeper into the samples that have been posted in the official docs. I ended up taking a hint from a Adi Roiban's post to another Angular e2e writer's question talking about query, done() messages, and promises. This ended up leading me to my eventual solution.
So I've made myself a solution and in the spirit of cooperation made a set of examples for others to learn by. There are four examples, the first two are just getting the text and the href and comparing them against hard-coded values. The third one uses indexOf to do dirt-simple comparisons. The fourth one shows how you can make your own more specific pass/fail conditions (more than what Jasmine provides with its matchers).
Number 1: User name text vs hard coded value
it('should have the user\'s name be \'PurplePenguin\'', function() {
var textPromise = element('.thumbnail__name:eq(0) > a:eq(0)').query(function (nameElement, done) {
var text = nameElement.text(); // Can finally access this guy!
// The first param null indicates a nominal execution, the second param is a return of sorts
done(null, text);
});
// Passes
expect(textPromise).toBe('PurplePenguin')
});
Number 2: Profile href value vs hard coded value
it('should have the user\'s link be \'/profile/PurplePenguin\'', function() {
var textPromise = element('.thumbnail__name:eq(0) > a:eq(0)').query(function (nameElement, done) {
var href = nameElement.attr('href');
// The first param null indicates a nominal execution, the second param is a return of sorts
done(null, href);
});
// Passes
expect(textPromise).toBe('/profile/PurplePenguin')
});
Number 3: Simple string comparison
it('should have the user\'s name match the link', function() {
var textPromise = element('.thumbnail__name:eq(0) > a:eq(0)').query(function (nameElement, done) {
var text = nameElement.text();
var href = nameElement.attr('href');
// The first param null indicates a clean pass, the second param is a return of sorts
done(null, href.indexOf(text)); // indexOf returns -1 if text is _not_ a sub-string of href
});
expect(textPromise).toBeGreaterThan(-1);
// In the case of failure reports this in the console (if using Karma):
// expect element .thumbnail__name:eq(0) > a:eq(0) custom query toBeGreaterThan -1
// expected -1 but was -1
// In the runner.html page for the test simply reports this useless/misleading log:
// expected -1 but was -1
});
Number 4: More detailed string comparison doing it your own way plus a better error message
it('should have the user\'s name match the link', function() {
var nameStringPromise = element('.thumbnail__name:eq(0) > a:eq(0)').query(function (nameElement, done) {
var text = nameElement.text();
var href = nameElement.attr('href');
var message;
if (href.indexOf(text) == -1)
message = 'Did not find "' + text + '" in "' + href + '"';
done(message, href.indexOf(text));
});
expect(nameStringPromise);
// An expect() with no Jasmine matcher means that it only uses the done message to determine
// a pass or fail for the test. So I wrote that if my conditions weren't met it would print
// an informative message in the case of failure
// Example failure output with a broken url generator:
// Did not find "PurplePenguin" in "/profile/"
});
I'm struggling to find references to back this up or explain a little more nicely, other than these docs which don't have much info. Therefore this answer is mainly from memory of reading the relevant code.
When you write a test in ngScenario, you are not writing a series of immediate actions as you would do in a unit test. What you are actually doing queuing up a list of commands to execute when the test starts.
Methods that looks like normal jQuery functions, such as text() or attr() are actually part of ngScenario's DSL and return future objects (meaning they will at some point execute and have the result of the call you wanted.)
expect() already knows this so waits for the result before comparing to your expected value. The code underneath, in your example, is reading directly and immediately so will see the future object.
If you do need to read the element in this way I suggest looking at the query function which should allow it. On the other hand if you need to just check the formatting of the string you can use toMatch which has been implemented in ngScenario too.

Categories