OnNavigatedTo vs Initialize(Async) - xamarin.forms

I am having a hard time to understand when to use Initialize and when to use OnNavigatedTo.
I understand that Initialize is execute once when the view model is initialized and OnNavigatedTo is executed every time I navigate to the page.
What is the best way on deciding what to do in Initialize and what to do in OnNavigatedTo?
Especially in a situation where I have data passed by navigation parameters but also fetched from additional apis (some even with http calls that can take a while)
Thanks a lot

Using Initialize will be triggered only when your ViewModel is created meaning you will have to destroy it and recreated it before triggering this method again.
OnNavigatedTo will be triggered every time your page (the one linked to this ViewModel) will appears, meaning it will be the case on the first navigation (same as Initialized) but also every time you will go back to this page.
So if you have the following navigation pattern: Page 1 > Page 2 > Go back to Page 1, Initialized will be triggered only on step 1 (creation of your ViewModel) while OnNavigatedTo will be triggered twice, once in step 1 and the other time on step 3.

Related

Troubleshooting: Redux & Redux Dev Tools -- Action "logjam" -- Actions are not appearing... then appearing all at once on next action

Problem
Actions in my redux store are appearing to log-jam behind one another. I'm iterating through a set of thunks, which each call a number of actions to show they've started, succeeded, etc. When this happens, an action appears for a second in redux dev tools, then is erased.
If I post another action, then all the actions appear all at once, like container ships following the ever-given.
Link to gif of the issue
In this gif I connect to a testing database, afterwards, a number of operations dispatch. I can see those operations in the console, but not devTools. Then, I post another action via the onscreen button, and all the actions flow through at once.
I'm hunting for instances of mutated state, but all reducers destructure state into a new object via:
let newState = {...state}
Any tips?
EDIT:
When I dispatch the same operation from behind a button element, it works just fine. The code that's log jamming is being called by an event listener attached to an event emitter... maybe this has something to do with it?
After debugging, I've traced the problem back to the redux replaceReducer method. I call it 3 times in this sequence. The first and second invocation works fine, but on the third - the store stops receiving actions.
store.injectReducer = (key, asyncReducer) => {
storeTools.dispatchAction({type:"STORE_INJECT_REDUCER_" + key})
store.asyncReducers[key] = asyncReducer;
let combinedReducers = createReducer(store.asyncReducers);
storeTools.dispatchAction({type:"STORE_INJECT_REDUCER_" + key})
store.replaceReducer(combinedReducers);
storeTools.dispatchAction({type:"RESET"})
console.log("replaceReducer")
}
^^^
This code prints actions on the first 2 invocations, but on the third, it prints the first two actions, but not the third.
This bug was caused by invoking "replaceReducer" multiple times within the same thread. From what I now understand - if you call replaceReducer in a forEach loop... you're gunna have a bad time.
My solution was to create a function that stages multiple reducers - then calls replaceReducer once.
May folks from the future benefit from this knowledge.

How does SetVaryByCustom work?

There are multiple ways to leverage ASP.Net MVC response/output caching. At the simplest you can cache a simple page that's the same for everyone:
[OutputCache(Duration=24*3600)] // cache 1 day
public ViewResult Index() ...
You can vary by specific params, you can bust the cache by a custom key. In all of those cases, the declarative OutputCacheAttribute is used to determine whether the page should just serve from cache. If it does serve from cache, the Action doesn't fire - CPU time saved.
So, suppose the Action accepts an Id, meaning its contents vary id to id. Suppose you want to bust the cache for specific Ids when their underlying data changes. MSDN says to set VaryByCustom inside the Action instead of declaratively in OutputCacheAttribute:
Response.Cache.SetVaryByCustom
Like:
[OutputCache(Duration=24*3600, VaryByParam="id")]
public async Task<ViewResult> Thing(string id)
{
Response.Cache.SetVaryByCustom("thing-" + id);
// Some big load of work we'd like to avoid when a ton of visitors hit
// the server goes here.
So... in every scenario until this one, that big load of work in the Action gets skipped if the page is valid in the cache. But it appears here it's not - unless SetVaryByCustom can interrupt the Action? How does this command work exactly?
If it doesn't interrupt the Action, is there some follow-on check I can do to see if the cache picked it up, so I can return early? And what would I return, given it's normally expecting a whole page filled with data?
Based on testing, it appears to work neither of the ways I proposed.
In my Action with this strategy applied, I:
Fire a log event
Fire SetVaryByCustom(id);
Fire another log event
And here's what I saw:
BrowserA: Visit a given id
Log: Both events fire - before and after
BrowserB: Visit same id
Log: (nothing)
BrowserA: Change id so an Invalidate fires for id
BrowserB: Visit id, sees 200
Log: Both events fire - before and after
BrowserA: Visit id, sees 200
Log: (nothing)
BrowserB: Visit id, sees 304
Log: (nothing)
In other words, the entire Action doesn't fire, just like in the static/declarative approach where it's all done in OutputCacheAttribute. What's pretty strange is each time it invalidates, the key gets an opportunity to change - you could pass a new key to SetVaryByCustom once per invalidation, but not more.
Unless you explicitly tell ASP.Net not to, the browser is also told to cache these pages, for the length of time remaining in the 24-hr period (via max-age). That means depending on how your visitors arrive, they may not see the page change as you intended. You can prevent this of course with Location=OutputCacheLocation.Server in your OutputCacheAttribute.
In any case, my core objective is in fact met - the server skips the CPU cost of the Action - just a bit more than I anticipated.

Why do my Firebase 'child_added' events show up out-of-order?

I have 2 "limit" queries on the same path. I first load a "limit(1)", and then later load a "limit(50)".
When I load the second query, the child_added events don't fire in-order. Instead, the last item in the list (the one returned by limit(1)) is fired first, and then all of the other items are fired in-order, like this:
**Limit 1:**
new Firebase(PATH).limit(1).on('child_added', ...)
Message 5
**Limit 2:**
new Firebase(PATH).limit(50).on('child_added', ...)
Message 5
Message 1
Message 2
Message 3
Message 4
I'm confused why "Message 5" is being called first in the second limit operation. Why is this happening, and how can I fix it?
I know this may seem strange, but this is actually the intended behavior.
In order to guarantee that local events can fire immediately without communicating with the server first, Firebase makes no guarantees that child_added events will always be called in sort order.
If this is confusing, think about it this way: If you had no internet connection at all, and you set up a limit(50), and then called push() on that reference, you would you expect an event to be fired immediately. When you reconnect to the server though, it may turn out that there were other items on the server before the one you pushed, which will then have their events triggered after the event for the one you added. In your example, the issue has to do with what data has been cached locally rather than something written by the local client, but the same principle applies.
For a more detailed example of why things need to work this way, imagine 2 clients, A and B:
While offline, Client A calls push() and sets some data
While online, Client B adds a child_added listener to read the messages
Client B then calls push(). The message it pushed triggers a child_added event right away locally.
Client A comes back online. Firebase syncs the data, and client B gets a child_added event fired for that data.
Now, note that even though the message Client A added comes first in the list (since it has an earlier timestamp), the event is fired second.
So as you see, you can't always rely on the order of events to reflect the correct sort order of Firebase children.
But don't worry, you can still get the behavior you want! If you want the data to show up in sort order rather than in the order the events arrived on your client, you have a couple of options:
1) (The naive approach) Use a "value" event instead of child_added, and redraw the entire list of items every time it fires using forEach. Value events only ever fire for complete sets of data, so forEach will always enumerate all of the events in order. There's a couple of downsides to this approach though: (1) value events won't fire until initial state is loaded from the server, so it won't work if the app is started in "offline mode" until a network connection can be established. (2) It inefficiently redraws everything for every change.
2) (The better approach) Use the prevChildName argument in the callback to on(). In addition to the snapshot, the callback for on() is passed the name of the previous child in in the query when items are placed in sort order. This allows you to render the children in the correct order, even if the events are fired out of order. See: https://www.firebase.com/docs/javascript/firebase/on.html
Note that prevChildName only gives the previous child in the query, not in the whole Firebase location. So the child at the beginning of the query will have a prevChildName of null, even if there is a child on the server that comes before it.
Our leaderboard example shows one way to manipulate the DOM to ensure things are rendered in the proper order. See:
https://www.firebase.com/tutorial/#example/leaderboard

ASP.net ajax : need best practices - updating steps on a page

I have an ASP.NET webpage that displays steps that must be performed server side. Those steps must be performed in the specified order, and the precedding step must be completed before the next one starts. For example, the steps would be:
1) Performing action A : Completed
2) Performing action B : In progress
3) Performing action C : Waiting
4) Performing action D : Waiting
When a step is completed, the corresponding status (Completed, In progress or Waiting) must be updated on the page.
So, how would you guys do that?
Here's what I have in mind:
The page calls a webmethod that performs the steps server side. When one step is completed, that webmethod updates a session variable that contains the step number and its status.
Then, every 5 seconds or so, the page calls another webmethod that checks the session variable and returns the step numbers that are completed. In javascript, update the status of the steps
Maybe there is a simpler way?
If it is possible that a person may close their browser & the steps should not be repeated, I'd consider using your DB or a cookie for the storage of steps and their corrosponding status.
It's the 'in progress' and 'waiting' that are the major cruxes of your problem as you won't be able to determine their state without some type of polling. I've done similar things before and used effectively the same method you described.

Flex's FileReference.save() can only be called in a user event handler -- how can I get around this?

I need to call FileReference.save() after a web service call has completed, but this method has a restriction: "In Flash Player, you can only call this method successfully in response to a user event (for example, in an event handler for a mouse click or keypress event). Otherwise, calling this method results in Flash Player throwing an Error exception." (from the documentation here)
This restriction is a bit vague. Does it mean that I can only call the FileReference.save() method from within an event handler function that is registered as a listener for certain types of user events? If so then exactly which user events are valid? (Perhaps there's an event that will never be dispatched by user interaction with my application and I could register an event handler function for that event type and make the save() call from within that function?)
My difficulty is that I can't safely call the FileReference.save() method until my web service returns with the data that will be used as the argument of the FileReference.save() method call, so the event that triggers the FileReference.save() call is actually a ResultEvent rather than a user event, and I'm leery of dispatching a new (faux) user event type in order to be able to trigger the FileReference.save() call unless it's definitely a user event that would never be dispatched as a result of actual user interaction with my application.
In a nutshell what I'm doing now is this: I have a function that is registered as a handler for a button click. In this function I make my web service call to fetch data from the server. I also have a result handler function which gets invoked when the web service call completes, and it's in here that I want to call the FileReference.save() method since it's at this point that I know that the data is ready to be saved to a file. But the aforementioned restriction is blocking me from doing this -- I get an error:
Error #2176: Certain actions, such as those that display a pop-up window,
may only be invoked upon user interaction, for example by a mouse click
or button press.
I've tried many things to get around this such as creating a second mouse click event handler function with the FileReference.save() call within and calling it after a timeout interval (to give the web service time to complete), but I keep running into the same error -- maybe that approach doesn't work since the second function isn't registered as an event listener for the event type used as its argument.
I'm new to Flex development so perhaps I'm just not thinking about this in the right way. If anyone can suggest another approach I'd really appreciate it. Thanks in advance for your comments or suggestions.
--James
Adobe does this as a sort of security measure to ensure users are the ones messing with files rather than potentially harmful code. My understanding is that they enforce this by only allowing handlers of (click?) events that originate from UI components to execute the FileReference methods, so generating your own events programmatically will not work, although I have not tried to verify this. Unfortunately the best resolution I've found is to re-work the UI a bit to conform to this constraint. In your particular situation, you could make this a two click process with a button that says something like "Prepare Download", which changes to "Download File" after the web service is complete. This is less than ideal from a user perspective, but I don't think there's much else that can be done unless you can somehow complete your web service call prior to displaying the button that triggers the FileReference.save() call.
After struggling for that for well, a couple hours I found a workaround: you can use both mouseDown AND mouseUp events instead of just click.
For instance:
s:Button
mouseDown="prepare_PDF()"
mouseUp="save_PDF()"
Works fine for me!
Happy coding!
--Thomas
As a workaround I used the ExternalInterface class. I created a javascript function with this code
function downloadFile (url) {
window.open(url);
}
An in AS3 I call
var url = 'www.example.com/downloadfile.php?file_id=xxx';
ExternalInterface.call('downloadAttachmentFile', url);
So with that I transfer the file handling to JS/HTML.
This is a comment on Thomas' answer (I don't have enough XP to comment yet): The mousedown and mouseup workaround works nicely. Just a note that if you make any changes in prepare_PDF() that need 'undoing' in save_PDF(), then its a good idea to call that code on the mouseout event as well, since there might be a case that the user mousedown's on the button, but then moves the mouse away from the button.
This was particularly relevant for my case, in which we increase the size of a watermark on an image when the user clicks the download button (that triggers the .save() call). I reduce the size of the watermark down to normal on the mousedown and mouseout events.
I had this same issue, I chose to use flash.net methods. Call flash.net.navigateToURL(url); from an actionscript or navigateToURL(url); from mxml.
What i do to solve this is to show an alert message with an anonymous function so i don't have to create a button.
Alert.show("Do you wish to download the file?", "Confirm", Alert.OK | Alert.CANCEL, this, function (eventObj:CloseEvent):void {
if (eventObj.detail == Alert.OK) {
fileReference.save(zipOut.byteArray, dateFormater_titulo.format(new Date ()) + ".zip");
}//if
}/*function*/, null, Alert.OK);

Resources