reactivex / learnrx Goto Github PK
View Code? Open in Web Editor NEWA series of interactive exercises for learning Microsoft's Reactive Extensions Library for Javascript.
A series of interactive exercises for learning Microsoft's Reactive Extensions Library for Javascript.
For exercise 41, the distinctUntilChanged() function is used to filter out successive repetitive values. However, when I enter a word with repetitive values aa
vs a
I get different results. Is this expected behavior? If yes, then the same function ( distinctUntilChanged()) does not behave the same way in exercise 40 - in that exercise, typing aa
will display a
. Exercise numbers refer to the tutorial found here: http://jhusain.github.io/learnrx/
Here is what I get by loading the page: https://jhusain.github.io/learnrx/
I haven't done anything, just loaded the page and looking at the console.
Uncaught TypeError: Cannot read property 'answers' of null
(anonymous function) @ main.js:29
x.extend.each @ jquery-1.10.2.min.js:4
x.fn.x.each @ jquery-1.10.2.min.js:4
window.onload @ main.js:24
window.prompt() in Chrome has limit for 3000 characters. As a result we may get invalid JSON if it's longer than 3000 characters. Not sure about limitations in other browsers.
If I give a name to the anonymous function and console.log() it,
I get this error:
"TypeError: movieLists.map(...).concatAll is not a function"
Hi wouldn't this code for reduce
videos.reduce(function(acc, video, index) {
acc[video.id] = video.title;
return acc;
}, {});
be better than using Object.create in your example
videos.reduce(function(accumulatedMap, video) {
// Object.create() makes a fast copy of the accumulatedMap by
// creating a new object and setting the accumulatedMap to be the
// new object's prototype.
// Initially the new object is empty and has no members of its own,
// except a pointer to the object on which it was based. If an
// attempt to find a member on the new object fails, the new object
// silently attempts to find the member on its prototype. This
// process continues recursively, with each object checking its
// prototype until the member is found or we reach the first object
// we created.
// If we set a member value on the new object, it is stored
// directly on that object, leaving the prototype unchanged.
// Object.create() is perfect for functional programming because it
// makes creating a new object with a different member value almost
// as cheap as changing the member on the original object!
var copyOfAccumulatedMap = Object.create(accumulatedMap);
copyOfAccumulatedMap[video.id] = video.title;
return copyOfAccumulatedMap;
},
// Use an empty map as the initial value instead of the first item in
// the list.
{});
A lot of the problems have solutions that require methods that are not explained or introduced in the text preceding the problem. Specifically on Exercise 10, I would have never arrived at the answer because .apply() was never explained to me. Even to this moment I have no idea what the .apply() method does in this specific piece of code, therefore resulting in me having to leave your tutorial and find the answers elsewhere.
This leads me to wonder, why use this tutorial at all if all the information I need is not supplied to me?
Coming to this as someone who is not familiar with the core methods in JavaScript, it has been a very frustrating experience and the only reason I will continue on with this is because it is a requirement from FreeCodeCamp to proceed through their tutorials. If a user who has never used JavaScript before came to this tutorial and was expecting to learn anything from it, they would get a bit of info, but nothing like the abundance of other tutorials out there that actually take the time to walk you through the code and explain everything.
My suggestion is to spend some time, perhaps do some user testing, find out where this tutorial is lacking and update it to be a solid tutorial. If you do not have the resources or interest in doing this, then perhaps removing it from the general public would be the best solution.
Up until Q12 it has been little steps, introducing new things, then combining them. Q12 combines a number of previous concepts but also assumes users will realise to use closures to reference values in previous operations.
This is unfair to the learner. You should never have questions that require specific knowledge that you either haven't previously used in exercises or or at least referenced.
I would suggest at least one preceding simpler exercise with "nested" maps where the inner one references the outer. Then you can through this complex one at them.
Hello, it would be really neat to have link to http://reactive-extensions.github.io/learnrx/ in the repo description so that people could jump into that at once, instead of scanning the readme for 'on-line' link that one can miss easily.
This page returns 404 now. Is there any migration?
This is a really great tutorial for Reactive newbies like me. Is there any plan for i18n support? It would be great if it's also available in other languages.
Array.prototype.concatMap is needed for use within this exercise, but it is not defined. Even if you choose 'Show answer', you get an error message in the alert message that says it is not defined.
Now that we know how to get only the distinct input, let's see how it applies to our autocomplete example...
should read:
Now that we know how to retry after errors, let's see how to catch exceptions...
I implemented concatAll()
method in the following way and it is marked to be correct by your tutorial.
Array.prototype.concatAll = function() {
var results = [];
this.forEach(function(subArray) {
subArray.forEach(function(element) {
results.push(element);
});
});
return results;
};
but when I clicked on 'Show Answer', it was using apply
method on push
, I was wondering why it was needed to use apply
method given it works fine without it?
Some exercises which are actually demonstrations don't have answers in the code. This causes them to lose the demonstration code when the user clicks the "Show all the answers so I can just browse." button.
Exercises affected:
I tried to open it on my chrome browser. It is not working at all. I press run button too many times.. Nothing happens. I did some changes on code. it throws me error all the time. Even though i copied answer from other location. I clicked on show all answer
nothing happens. I thought i is the prob with chome. I tried it on Firefoz though, Result is same. Run still not woking. Somehow show all works on firefox. But excep that nothing is working. Please check. I have mention all required detail below. Examples are too good. Thanks ๐
Google Chrome
Version 43.0.2357.81 unknown (64-bit)
Firefox
38.0
System:
Ubuntu LTS 14.04
In Exercise 30, .take(1)
doesn't seem to have any effect. On the first button press the alert appears 2-3 times and then on every subsequent button press, a single alert appears. I was testing with the answer provided.
Running on Chrome Version 48.0.2564.97 (64-bit)
Comment for exercise 22 starts with the following:
// JSON.stringify(Array.zip([1,2,3],[4,5,6], function(left, right) { return left + right })) === '[5,7,9]' accumulatedValue + currentValue; }); === [6];
The part accumulatedValue + currentValue; }); === [6];
seems to be pasted from exercise 16 by accident.
On exercise 24, I wrote my solution, ran it and... didn't match the expected output. I started debugging, I printed out each of my results, and they looked correct. So then I showed the solution, and compared each property of each of the resulting objects... also correct. So I printed both to the console; they also matched. Then I finally admitted defeat and actually looked at the solution code. The only difference I could see was the following:
solution:
return {id: video.id, title: video.title, time: interestingMoment.time, url: boxart.url}
mine:
return {id: video.id, title: video.title, url: boxart.url, time: interestingMoment.time}
In case you weren't reading closely, the only difference was the order the url and time properties were added to the returned object. I swapped the order and, lo and behold, it works. Looking at the source code, it looks like this is because the results are compared by sorting the resulting array, stringifying the results, and then comparing the result strings. Unfortunately, most browsers iterate over object properties in the order they were added, so two objects which have the exact same properties and values will NOT produce the same JSON.stringify strings.
Is there any particular reason to avoid doing property based comparisons, that is, checking to ensure both objects have the exact same set of property keys and associated values, as opposed to using the string-based comparison? I would be happy to implement the changes and submit a pull request if that would be amenable.
Thanks
Useful to do the exercise in differents browsers... You can save the answers in you email or evernote, and set the answers in another browser to continue the exercises.
The sample answer for Exercise 40 doesn't work in firefox because of https://bugzilla.mozilla.org/show_bug.cgi?id=112379 .
The code uses String.fromCharCode(e.keyCode) where e is keypress event. Firefox uses charCode for events which generate characters.
It felt wrong to look at the data and craft the query based on a hard value based on that. It would be nicer if the question was phrased something like: "Use mapMany() to retrieve id, title, and a 150px wide box art url for every video"
Hi.
It took a day or two for me to get an explanation on why Object.create is necessary in this exercise (being that the exercise will work quite well without creating a new object). Tell me if I'm right. You want to create that new object only if you want that object to survive after the reducing is finished... so you can use that object elsewhere in your code. Even though the object is returned from the reduction. Am I close?
A little more explanation would be helpful.
Thanks for the tutorial so far!
this line:
Let's repeat exercise 19, but this time let's use your new zip() function.
should read:
Let's repeat exercise 21, but this time let's use your new zip() function.
While trying to solve the third puzzle, I had to consult a JS API reference to find "push()". After doing more puzzles it struck me that I could solve them without having to look at the doc again, so in retrospect it would be nice if the early puzzle mentions "push()" so I could have stayed focused on the page :-)
Greetings.
I found a mistake in the right answer, i believe.
Array.zip() by definition takes 2 arrays and a function as arguments.
But when we are using the result of reduce function on an array of objects as an argument for our Array.zip() function, it will return a single object, not an array with an object in it.
I was able to fix it by wrapping return result of reduce function with square brackets.
return Array.zip(
video.boxarts.reduce(function(acc,curr) {
if (acc.width * acc.height < curr.width * curr.height) {
return [acc];
}
else {
return [curr];
}
});
Am i correct on this or am i missing something?
Thank you.
I have attempted a solution to exercise 26: Converting from Arrays to Deeper Trees, without success ('undefined is not a function'). I have asked to see the hidden solution and it is practically identical to mine: the proof is that... the given solution gets the same error alert!
If I substitute in both mine and your solution the concatMap
with a plain map
I get the 'wrong result' message and I can see that the items in the videos arrays need some flattening (see image).
However, also if I put a concatAll()
after the map
I get the 'undefined is not a function' error.
The consequence is that it is not possible to proceed further in the tutorial, since the right solution triggers the error message. The only way to proceed is to ask beforehand to see all the answers, which is definitely not in the spirit of this activity.
Thank you for your attention.
Minor inconvenience: working on the drag exercises, one often accidentally 'selects' (as in text highlighting) a large portion of the viewport, as well as the div itself. This isn't a problem but it's annoying.
It would be nice if this didn't happen.
I'll work on a PR later, but here's what I'm using to guide me, if anyone wants to beat me to the punch:
http://stackoverflow.com/questions/826782/css-rule-to-disable-text-selection-highlighting
The link to view the tutorials online does not have an associated href attribute, and therefore does not link to anything.
I think we'd all really like to know where that link is suppose to lead! ๐
After sending a PR, i realized that my changes wouldn't make it over to the tutorial site because i sent the patch against the master branch instead of the gh-pages branch.
i would suggest getting rid of the master branch because this project can just work off the gh-pages branch and the site would be unaffected. i think it will grease the skids for future contributors/contributions.
This was mentioned in comments of other issues, but I think it warrants it's own issue. The reduce
implementation in the tutorial returns an array, not an object, which goes against the JS spec. For those people coming to this tutorial who are already familiar with JavaScript, this is more than a little confusing.
I'd recommend either:
Great tutorial! Lots of fun to go through the exercises.
Howdy. I'm loving the interactive nature of http://reactivex.io/learnrx/. It is awesome.
However, my quasi-functional brain is having a hard time digesting the approach in exercise 12 (and consequently 20) that calls for mapping the boxarts without an index into the array.
Here is my code that is apparently offensive because it wants to do an index (My C# Linq brain says FirstOrDefault!):
return movieLists.
map(function(ml) {
return ml.videos.map(function(v) {
return {
id: v.id,
title: v.title,
boxart: v.boxarts.filter(ba => ba.width === 150 && ba.height === 200)
.map(ba => ba.url)
[0] //<< this isn't "allowed". firstOrDefault equivalent(?)
};
}
);
}).
concatAll();
Without the indexer, this comes up with the "right" answer, in that it is an array with a single element. However, the resulting boxart
element is an array and without the indexer (or FirstOrDefault) it is utterly wrong because of this.
Here is the correct answer:
return movieLists.
map(function(movieList) {
return movieList.videos.
map(function(video) {
return video.boxarts.
filter(function(boxart) {
return boxart.width === 150;
}).
map(function(boxart) {
return {id: video.id, title: video.title, boxart: boxart.url};
});
}).
concatAll();
}).
concatAll();
To my non-functional brain, this was extremely ugly. I can sense that perhaps this is a nested collection, and that this is possibly related to an unfolding of an abstract construct in the functional world. However, this just doesn't seem to scale to me.
Say I were to add a second array property similar to boxarts, like relatedtitles and I had some predicate to reduce it to a single value. With my approach, you would just add another line that takes the additional properties and filter+map them. How would the corresponding functional approach look?
With this question of scalability in mind, is this just an example to get the tutorial going? Or is there something a real functional guru can shed some light on this? Or should I just keep doing the exercises!? I was avoiding asking this question at exercise 12, but then the reduce exercise 20 brought me back to it. Am I asking the question too soon? If I keep watching the movie, will all be revealed and the universe will be in harmony?
I love the exercises though. This is the best functional + Rx tutorial I've seen over the past couple years.
there is a problem with contactPoint event object โ there are no offsetX and offsetY properties.
Hey I submitted an answer which contained the same objects but in a different order and it was evaluated as incorrect. My solution preserves the order of the objects in the input.
return movieLists.concatMap(function(movieList) {
return movieList.videos.map(function(v){
return Array.zip(
v.boxarts.reduce(function(acc, curr){
return curr.width * curr.height < acc.width * acc.height ? curr : acc;
}),
v.interestingMoments.filter(function(item){
return item.type == "Middle";
}),
function(left, right){
return { id: v.id, title: v.title, time: right.time, url: left.url };
}
);
});
});
I have solved Exercise 12, but I can't go any further because, when I click on run this error pop up ( TypeError: movieList.videos.map(...).concatAll is not a function ).
I haven't been able to figure out the exact cause, but in some of the editor windows, pressing F4 to try to enter full-screen editing causes the page to freeze up and eventually causes Chrome to say the page has stopped responding and ask to kill the tab. Reloading the tab brings the page back up, but trying to hit F4 on the same editor box repeats the problem.
Currently using Chrome 44.0.2403.52 beta-m (64-bit)
There's an older, forked repo here: http://reactive-extensions.github.io/learnrx/
That repo looks like it diverges around exercise 10 with mergeAll.
Of course anyone can fork a repo, but that one looks like an official repo from MicroSoft but hasn't been updated for a ~1.5 years, whereas this repo looks active. Adding to the confusion (at least mine), this repo points to their exercises in the readme, as opposed to http://jhusain.github.io/learnrx/
A couple suggestions:
hello, rookie here, trying to implement drag on a small web app, not sure what Im doing wrong
(i included the code here because it is just a couple lines of code, nothing fancy in html and css)
(function (global) {
function dragger(){
var $sprite = $('.sprite');
var $spriteContainer = $('.container');
var spriteMouseDowns = Rx.Observable.fromEvent($spriteContainer, "mousedown")
var spriteContainerMouseMoves = Rx.Observable.fromEvent($spriteContainer,"mousemove")
var spriteContainerMouseUps = Rx.Observable.fromEvent($spriteContainer,"mouseup")
var spriteMouseDrags =
spriteMouseDowns.
map(function(down){
return spriteContainerMouseMoves.takeUntil(spriteContainerMouseUps);
}).
concatAll();
spriteMouseDrags.forEach(function(dragPoint){
$sprite.style.left = dragPoint.pageX + "px";
$sprite.style.top = dragPoint.pageY + "px";
});
};
dragger();
}(window));
When you come back the the page to continue the tutorial, you need to re-run the exercises 10 and 13, or the other exercises needing concatAll() and concatMap() won't run. These function should be automatically added to Array.prototype by the browser, when it finds related data on local storage.
In the exercise, Object.create is used to "create a fast copy of the accumulated map".
I don't see what's fast or useful about using Object.create instead of simply mutating the map.
I ran tests, and I see no reason why Object.create should be used instead.
After completing all 42 questions I wanted to save my state locally as advocated possible at top of the page.
Only to find out the data posted to my clipboard by Safari is no longer than 32000 characters, leaving me with an incomplete dump of my state.
Correction: it is Safari 8.0.8 (only browser tested by me) that initially only selects the first 32000 chars in the popup, re-selecting the JSON grabs the full (in my case) 52k chars.
I have no idea how the browser is told to make the text (conveniently) pre-selected in the pop-up, so this might not be a bug for this repo.
Ps: liked the tutorial a lot, very educational.
CodeMirror checks for and uses map on Array.prototype if it is defined.
see it on codemirror.js L7213
function map(array, f) {
var out = [];
for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
return out;
}
if ([].map) map = function(array, f) { return array.map(f); };
solvable by commenting out/removing line 7213
function map(array, f) {
var out = [];
for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
return out;
}
- if ([].map) map = function(array, f) { return array.map(f); };
Hi!
If I click Run
then refresh the page I can get the next exercise without writing any code.
Hi, I was following the tutorial and noticed that on exercise 16, where reduce is implemented using a while
and a counter
, effectively determining how the array should be traversed. Check the code below
while(counter < this.length) {
accumulatedValue = combiner(accumulatedValue, this[counter])
counter++;
}
I just started studying RX but, as far as I get it, one of the key points is to leave to the underlying libraries decide how to traverse the arrays? If so, I think the reduce could be better implemented like this:
var accumulatedValue;
if (arguments.length === 1) {
counter = 1;
// DON'T SET IT TO ANY ELEMENT
// accumulatedValue = this[0];
}
else if (arguments.length >= 2) {
counter = 0;
accumulatedValue = initialValue;
}
else {
throw "Invalid arguments.";
}
this.forEach(function(it) {
if(typeof accumulatedValue == 'undefined') {
accumulatedValue = it;
}
else {
accumulatedValue = combiner(accumulatedValue, it)
}
})
It says that exercise 42 is about learning how to retry after errors, but it's actually just a copy of the "Distinct Until Changed Input" exercise (40). Verified this was true in the index.html in this repo as well.
Not necessarily a show stopping issue but something that I found annoying. I'm guessing it's locking up the browser because of all the painting that's happening for answers.
In Firefox 19.0.2, I see this following error when trying to run the first exercise:
TypeError: verifier is not a function
Please comment. Thanks
I've just executed the workaround for this bug, and this is printed to the console:
HTMLElement.prototype.innerText = function() { return this.textContent; }
function()
I now see the first three tests, but when I click "run", nothing is printed to the console. On the third test, however, when you click "Show answer", the following error is printed to the console:
TypeError: string.split is not a function
http://reactive-extensions.github.io/learnrx/assets/codemirror/codemirror.js
Line 3124
Otherwise, no output. I'm on Firefox 35.0.1, Windows 8.1, 64bit. I have the NoScript 2.6.9.10 Firefox plugin installed, but it's currently set to "Allow scripts globally" (which is temporary only for this tutorial). I also have Ghostery and AdBlock Plus, if that makes a difference.
If I console.log() the result of this exercise, it is not like the expected one:
[
{
"65432445": "The Chamber",
"675465": "Fracture",
"70111470": "Die Hard",
"654356453": "Bad Boys"
}
]
it looks like this:
[
{
"654356453": "Bad Boys"
}
]
Is the expected output wrong or just the solution?
Thanks for the great Exercises at all.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.