Check out a free preview of the full Asynchronous Programming in JavaScript (with Rx.js Observables) course
The "Syncing Data with the Server" Lesson is part of the full, Asynchronous Programming in JavaScript (with Rx.js Observables) course featured in this preview video. Here's what you'd learn in this lesson:
While two-way binding in the application is nice, the changes reflected in the model and view should also be synchronized with the database. Jafar expands his example to include a database request as the model data is changed.
Transcript from the "Syncing Data with the Server" Lesson
[00:00:00]
>> [MUSIC]
[00:00:03]
>> Jafar: What we were gonna try and do originally, we were going also to try and set it up so that if we change the model, we would write the data to the server, right? We wanna just have it implicitly sinking back to the server, every single time somebody changes the model.
[00:00:17]
So object observe can be our way of doing that. So instead of directly forEaching over this, I'm going to create an intermediate observable personChanges, and then we are going to subscribe or forEach over person changes. But now, I also have this observable that I can forEach over that I can use as part of a larger observable expression.
[00:00:38]
So now we're gonna create the stream of data that we want from the stream of data that we have. So, I'm gonna create a fake function here, just a function that,, saveToDB.
>> Jafar: And it's going to accept, actually it's not gonna do anything. It's just gonna use the person object every single time.
[00:00:58]
It's gonna save the person object to the database. Now it's not really gonna do that because I don't have any database open. But we know that that operation would be asynchronous, right? It would return, so we return an observable. So I can kind of fake it because observable has a little timer method.
[00:01:14]
All right, I believe it's timeout actually. And you can just give it a time, and now what does it do? It'll fire, so under the hood it is. Yes, a question?
>> Speaker 2: How can you wait until both name and age is changed before you're reflecting that on the model?
[00:01:28]
>> Jafar: Well the good news is, well actually that depends what he means, because if you change first name and age, right, all synchronously then you're only gonna get one object observe callback. But if we do it through the form, in other words, we change name and then we change age, then yes we'll actually get two object observe callbacks.
[00:01:49]
So we'll write it to the database every single time. So, that's a good question. If we only wanna do something after every field is changed. It's kind of a tricky one. And the idea is, so we only wanna make a change after every single thing. I don't know how realistic that case is because in practice, you probably only wanna either wait for a save to occur or that somebody explicitly clicking Save or you'd probably wanna sync after every single field changes.
[00:02:18]
But that's kind of a fun thought experiment. You guys already know how to do it actually.
>> Speaker 3: It's very similar doing auto complete isn't it?
>> Jafar: Kind of similar yes but the operator, exactly the operator to use for this case. Let's imagine that we could create a stream of name changes and a separate stream of age changes.
[00:02:39]
Right now we have object observations which fires regardless of whether name or age fires. It's one stream but we can split it into two streams, one which only fires if the name changes and another one which only fires if the age changes. Yes?
>> Speaker 2: Could you use zip?
[00:02:55]
>> Jafar: Yes you could. If you took that object observations and you split it into two, one where it was only name changes and one where it was only age changes and you only wanted to save the database. When they changed the name and age, you could use zip because then you'd zip those two things together and then it would only fire after what you got one from name and one from age.
[00:03:16]
Now there's actually a better operator to use though. So zip would work but it would be a little bit weird because let's say I go to name and then I tab away and I change name again and then I tab away and then I change name again and then I tab away.
[00:03:28]
What zip will do on next to a value, it needs to have one from both name and one from age. So it actually buffers, it buffers up all the names. So then what would happen if you change name three times, and then you wouldn't change age once, it would save the database.
[00:03:43]
And then you change age again, it would save the database. You change age again, it would save the database. And then the left hand side, all the items would be removed, it would be stopped. So zip is great when you're working with observable for those case where you have two network requests.
[00:03:55]
And usually two observables of one or n observables of one. And you wanna wait till they all finish. But for cases like this. Sorry?
>> Speaker 3: MergeAll?
>> Jafar: MergeAll only works on observables of observables. And with this case, we would have two observables, in our hands, at the same time.
[00:04:10]
We have the stream of name changes and the stream of age changes. But there's actually a perfect operator in our x design for exactly this type of thing. We wanna save to the database, it would either of these fields change but if you change name twice. Right, well let me put that we see if that's actually the correct operator.
[00:04:29]
For this is a bit of a weird case. Because you, only when you change both of these operators. Technically, probably what you'd wanna do is you'd wanna wait until name change. And then age changed before saving. And then if either name or age change in the future. You'd probably wanna save, right?
[00:04:43]
It would be very weird to wait for them to change off, it's just a weird case. We could probably make it work, it's just not realistic. So I'd rather focus on the realistic cases. And my guess is the most realistic case is that if any of these things change, you probably wanna save to the database.
[00:04:58]
>> Speaker 3: Updating password
>> Jafar: Yeah.
>> Speaker 3: Would be a good example. We need both fields if changed.
>> Jafar: Because you have your password and then the confirm password?
>> Speaker 5: Yeah, the confirm.
>> Jafar: But even in the confirm, right? Would you change it as soon as they synced up their confirm?
[00:05:13]
To me that would actually be a very bad UX, because I would wanna take an explicit action to change my password. I wouldn't wanna just happen to enter something into a text box, right?
>> Speaker 6: It's just an [INAUDIBLE] You'd want validation.
>> Jafar: You'd want validation, etcetera, right? So, but one thing I wanna bring your attention to.
[00:05:29]
Because it's a very common pattern in UIs is, generally speaking, it's either if somebody takes an explicit action to say save or if any field changes, you wanna save. Those are the two actions. Question in the back.
>> Speaker 7: What's the point of rx.subject?
>> Jafar: So a subject is a topic I was hoping to get to today, but I'm not gonna be able to get to.
[00:05:50]
That's okay, because for the most part RX developers don't need to use them. So I don't know how deep I wanna go into that. We can leave that for another time, or you can check that out in the documentation, but in practice you shouldn't find yourself using subjects very much.
[00:06:03]
So I don't wanna focus on it too, too much. So I'm a little reluctant to answer that question. It's more advanced topic and as you can see we've done a heck of a lot without ever using a subject. So that's kind of why I'm not super eager to introduce the topic right now and that's okay.
[00:06:18]
But we can always handle that question by e-mail after the fact or something like that maybe we can explain that.
>> Speaker 7: Or in your next round when you come back.
>> Jafar: Or in my next round when I come back, we do an advanced RX. [LAUGH] Yeah. So I do you wanna introduce you to one more operator because it is very useful for exactly this case and it's like the cousin of zip.
[00:06:40]
So how does zip work? Zip, remember the zipper? Where you need to zip up and you need a tooth on either side, otherwise the zipper gets stuck, all right. Combine latest is very similar to zip, except the way it works is instead of waiting for an item from each side in order to advance.
[00:06:58]
If a new item comes in either of the left hand side or the right hand side, it immediately [INAUDIBLE]. As long as it has at least one item from the left hand side, then if another item comes down from the left hand side instead of waiting for a corresponding item from the right hand side, it just on next with the last item that it got from the right hand side.
[00:07:18]
So the very first time it needs to wait for at least one item on the left and at least one item on the right. So combine latest here would actually be kind of close to what we need. Imagine we created a stream of names and a stream of age changes and then we did a combined latest on it.
[00:07:30]
Well, we wouldn't save to the database until somebody changed both name and age. But then after that if they changed either name, or age, we would send off to save the database. Because what happens is the function gets called with the last value of name. If you change age, or if you change name, it gets called with the last value of age.
[00:07:47]
Hence the term combine latest. So the latest value that comes on the left hand side. It just takes the old value on the right hand side and immediately calls. Whereas zip would wait for another value to arrive on the right hand side before calling the function, combinelatest. So that's very useful when you tend to work with you UIs.
[00:08:04]
And you're doing that type of really reactive application where every single time a field changes, you wanna go and sync up with the database. So, why don't we do something a little bit more, I mean, to me, the most realistic case here is that, when any field changes, we wanna save to the database, right?
[00:08:21]
It's either that, or there's a save button. And so, let's go with the other kind, where any field is changing, and we wanna save to the database. So, we're gonna make a fake function, and all it's gonna do is just create an observable that takes 500 milliseconds to complete write and then returns.
[00:08:36]
Nothing. I believe I'm not sure if it returns an on next with like null it and then nothing or just is empty. We'll find out one way or the other. So if I call this SaveToDb function. And then I forEach over it, we'll see if it actually has a value in here or it's just an empty observable.
[00:08:55]
Now it's totally possible that timeout could just literally be an empty observable, one that looked like
>> Jafar: This. Nothing wrong with an observable like that. If I was to model an animation as an observable, which is too bad we didn't get to in this class but it would be fun.
[00:09:13]
Next time you wanna try animations out and you wanna coordinate them. Actually I definitely wanna talk a little bit about that. Because it's some very cool stuff, right. I'll come back to that. So an observable, right. If I was to model an animation as observable. Sometimes an observable just doesn't really have any data.
[00:09:29]
It just a duration of time and then it completes and animation's a good example of that, right. It just sort of like, you would model most animations as an observable that just go on until they're done. And you just need to know that the animations done. Now another way of handling that would be like, imagine you are animating a box from left to right.
[00:09:45]
X, left to right, right. You could keep on nexting like the individual X and Y, the X and Y positions as the animation went on. But in practice that's probably not very efficient number one. And number two, nowadays we typically do animations using things like CSS transitions. And the way CSS transitions work is they don't keep calling you with their intermediary values cuz it's not very fast.
[00:10:04]
Right, they just call you. They can usually call you to tell you when they're done though. And so that's why it's very convenient, to model a CSS translation, transition, excuse me, as an observable.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops