-
Notifications
You must be signed in to change notification settings - Fork 164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Question about SubscribedBy method #120
Comments
It may help to look at it in terms of the original Rx APIs: Publisher_TypeA.SubscribedBy(Subscriber_TypeB, TypeA_To_B_Mapper)
// is equivalent to
var Publisher_TypeB = Publisher_TypeA.Select(A => Type_A_To_B_Mapper(A));
Publisher_TypeB.Subscribe(Subscriber_TypeB); So the mapper gets called every time Publisher_TypeA emits a value. Since it is an async get, new data it produces must be pushed manually, so we'll have to break the chain apart and write it like this: _selectedUserId.Subscribe(async id =>
{
var user = await _userService.GetAsync(id);
(subVM.User as ReactiveProperty<User>).Value = user;
PushUpdates();
}); Hope this helps! |
Ah, that does make a bit more sense but I definitely need to learn more about the observer pattern. So, your solution did work (thank you!) but there is a bug which is either something with my code or the async nature of the lambda. The form field updates but it is sometimes one selection behind. For example, the first selection doesn't update the form (but in the debugger I can see that the proper entity from the database is being set on the subVM), but then my second selection updates the field with the first selection's entity. What's odd is that stepping through with the debugger, I can see the correct current selection getting set on the subVM and then PushUpdates getting called, but the actual value that is pushed to the React component is the previous selection's entity... However, I can sometimes get it to update the form with the actual selection depending on how fast/slow I click around on the DataGrid, but I don't notice any pattern to it. Do you think it has to do with the async call? |
You can test whether the problem is with async by temporarily forcing it to
be synchronous with .Result.
Also turn on dotnetify.debug and check the browser console log whether the
correct value is being sent.
…On Tue, Sep 25, 2018 at 6:24 PM debuggingmyhead ***@***.***> wrote:
Ah, that does make a bit more sense but I definitely need to learn more
about the observer pattern.
So, your solution did work (thank you!) but there is a bug which is either
something with my code or the async nature of the lambda. The form field
updates but it is sometimes one selection behind.
For example, the first selection doesn't update the form (but in the
debugger I can see that the proper entity from the database is being set on
the subVM), but then my second selection updates the field with the first
selection's entity.
What's odd is that stepping through with the debugger, I can see the
correct current selection getting set on the subVM and then PushUpdates
getting called, but the actual value that is pushed to the React component
is the previous selection's entity...
However, I can sometimes get it to update the form with the actual
selection depending on how fast/slow I click around on the DataGrid, but I
don't notice any pattern to it. Do you think it has to do with the async
call?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#120 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AOS8kv6hdb_hNO1Pi8grctN4tfdAzAKjks5uetdQgaJpZM4W5Z8y>
.
|
Well, it seems the problem is indeed with async. If I use a non-async lambda and use .Result on my repository method like you suggested, it works exactly as it should (i.e. the form updates with the correct selection, no matter how fast or randomly I click around the grid). I suppose I should dig around and see if there is another way to implement async with Subscribe. On a related note, would you recommend maybe not using async methods for my repositories? It seems like it would simplify things when using DotNetify. Admittedly, I only set everything up as async because when I was learning MVC I kept seeing all the examples set up that way (and also I kept reading that when dealing with the database I should be awaiting async methods). |
Async won't hog the thread if it's doing expensive operations like DB access, so definitely keep it. Do check the browser console log if the right value is being sent. I'll test async with the form example in case the bug is dotNetify's, and will let you know. |
Thanks, appreciate the help! I did enable dotnetify.debug and when it's async, I can see that it sends the correct selected id # to the ViewModel but then sends the previous selection's object back (except for the times when it syncs properly). |
I was able to reproduce your issue and got to the bottom of the problem: the The best solution for this is to add a new property in the master VM to process the async operation, so that there will be data change on the master VM when the async call returns a value. Then get the sub VMs subscribe to this property: OnSubVMCreated()
{
if (_selectedUser == null)
{
var update = AddProperty<bool>("Update");
_selectedUser = AddInternalProperty<User>("User");
_selectedUserId.Subscribe(async id =>
{
_selectedUser.Value = await _userService.GetAsync(id);
update.Value = true;
PushUpdates();
});
}
(subVM.User as ReactiveProperty<User>).SubscribeTo(_selectedUser); |
With the just-published Nuget v3.1, dotNetify now supports async reactive methods SubscribeToAsync and SubscribedByAsync, as well as adding new PushUpdates overload to force other view models on the same connection to update even though the calling view model doesn't have one. The above can now be written like this: constructor()
{
_selectedUser = AddInternalProperty("User", default(User))
.SubscribeToAsync(_selectedUserId, async id => await _userService.GetAsync(id));
}
OnSubVMCreated()
{
(subVM.User as ReactiveProperty<User>)
.SubscribeTo(_selectedUser)
.Subscribe(_ => PushUpdates(true));
} |
.Subscribe(_ => PushUpdates(true)); where is this |
That’s from System.Reactive namespace. |
I'm currently creating a simple user management page and am using the Customer Form example (from Elements) to help guide me.
Similar to the example, I have a form that will be populated based on the current selected User in the DataGrid.
In my OnSubVMCreated method, I was going to use the following code (similar to the example):
However, my repository methods are async, which I know doesn't work in SubscribeTo/SubscribedBy. So instead I was going to use something like:
But then it occurred to me that I don't actually understand what is happening with SubscribedBy, so I don't know how to recreate what it is doing.
I looked through your code and it seems SubscribedBy calls subscriber.SubscribeTo(mapper(property)), which eventually calls property.Subscribe(subscriber), if I'm understanding it correctly.
What I don't understand is, using the original example, how is "id => _userService.Get(id)" getting called every time _selectedUserId changes? I'm sure I'm missing something and/or not understanding the Reactive stuff, but to me it looks like the end result of SubscribedBy is just having the ReactiveProperty observing the changes to _selectedUserId.
I guess my main questions are:
How does the mapper function in SubscribedBy get called every time? Or if it doesn't, then in the Customer Form example, how is the applicable Customer entity getting pulled on selection change?
Is there a way to recreate what it's doing but in an asynchronous manner?
Should I instead just have the SubVM subscribe to an Event on the parent VM?
Sorry for the wall of text and hopefully my question makes sense. I'm having a hard time wrapping my head around this and any help is appreciated.
The text was updated successfully, but these errors were encountered: