I have a situation where as soon as app starts i have to call a web service to post unsaved data back to the server while i keep on accessing the app. I should be able to navigate to different views, perform UI tasks.
I can use Task
Task CallWebService()
{
return Task.Factory.StartNew(() => {
// make your service call.
});
}
CallWebService().ContinueWith(task => {
if(task.isFaulted)
throw new AggregateException(task.Exception.InnerException.Message);
// Runs when the task is finished
InvokeOnMainThread(() => {
// Hide your activity indicator here.
StopActivityIndicator();
});
});
I dont know where to call InvokeOnMainThread as user could be on any view. How do we handle that.
I would create the downloader as a static class with event handlers (or use dependency resolver). In your view controllers override ViewDidAppear and ViewDidDisappear where you will subscribe and unsubscribe to the events.
In your AppDelegate.cs, You can add your "Task" to the FinishedLaunching override and the OnActivated override, assuming you have a way to determine if there is any "unsaved" data, that needs to be sent to the server.
public override void OnActivated (UIApplication application)
{
}
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
}
Related
I'm new with NgRx.
I made some code, but the result is not exactly what intended.
I would like to intercept every action sent with the dispatch() function to the store.
My goals are the following:
intercept every action sent to the store in a custom Effect, and print the text (Intercepting action...) to the console without modifying the action. (The Effect, that handles this action, should work normally.)
if the action (that was previously sent to the store) made its job (i.e. the corresponding Reducer made modifications on the store), I also want to "react" on this, and print another message (Got state from store.) on the console
I have 2 problems in my code:
the texts appear in the wrong order (i.e. first "Got state from store", then "Intercepting action...", then "Got state from store" again).
to intercept every action, I make an array of all of the actions, defined in the application, and call ofType() with this array. If a new action is implemented, I have to manually update this array. Is there a way to retrieve the registered actions directly from the store ?
Below is the code:
app.module.ts
//to register the Effect to intercept the actions
imports: [
EffectsModule.forRoot([InterceptorEffects]),
]
app.component.ts
//here I react to the changes of the store
_interceptorSubscription: Subscription;
this._interceptorSubscription = _store.pipe(select((state, props) => console.log("Got state from store.")) );
interceptor.effect.ts
//the Effect that should intercept every action
#Injectable({ providedIn: "root" })
export class InterceptorEffects {
private readonly _interceptAllAction$ = createEffect(() =>
this._actions.pipe(
ofType(...[JobActions.downloadResultAction, JobActions.deleteJobAction]),
tap(() => console.log("Intercepting action..."))
)
, { dispatch: false } );
constructor(private _actions: Actions) {}
}
Thank you for any advice.
May I ask why you need this?
To answer the question:
AFAIK you can't do this. An action first reaches all reducers, and then it's handled by effects. If you want to register actions BEFORE they reach a reducer, take a look at meta reducers.
To react to all actions in an effect, don't use the ofType operator, and simply subscribe to the Actions stream.
I'm working with emberjs during some time and now I want to refine my understanding of ember's nature.
Question 1.
Am I right that the route's model() hook is the best place to write asynchronous code (to get all needed data)? Should I try to place all my network requests (or at least most of them) inside routes' models?
Question 2.
The component hooks have synchronous nature. Does that mean it's a bad decision to write async code inside hooks?
Say, I have async init() hook where some data is calculated and didRender() hook where I expect to use that data. When ember calls init() it returns a Promise, so it's moved from a stack to a special queue and ember doesn't wait until event loop returns that code back to a stack. So ember runs next hooks, and when didRender() is being executed the init() hook may not be fulfilled and the expected data may not exist. Is that right?
Question 3.
Services hooks should also be synchronous. Because when a service is injected inside a component and is used ember also doesn't wait until the async hook is fulfilled.
Say, I have a shopping cart service with products property. The products ids are stored in localstorage and I want to get those products from a server to set them into products property.
import Service from '#ember/service';
import { A } from '#ember/array';
import { inject as service } from '#ember/service';
export default Service.extend({
store: service(),
init(...args) {
this._super(args);
this.set('products', A());
},
async loadProducts() {
const cartProducts = A();
const savedCartProducts = localStorage.getItem('cartProducts');
if (savedCartProducts) {
const parsedSavedCartProducts = JSON.parse(savedCartProducts);
const ids = Object.keys(parsedSavedCartProducts);
if (ids.length > 0) {
const products = await this.store.query('product', {id: Object.keys(parsedSavedCartProducts)});
products.forEach(p => {
p.set('cartQuantity', Number(parsedSavedCartProducts[p.id].qty));
cartProducts.pushObject(p);
});
}
}
this.products.pushObjects(cartProducts);
},
...
});
If I call loadProducts() from service's init() I can't use this.cart.products in controllers/application.js, for example. Because service is ready, but async init() is still executed. So, should I call it in routes/application.js model() hook?
Question 4.
If there is some general component that doesn't refer to any route, but this component needs some data from a server where should I make async requests? Or are computed properties and observers are the only solutions?
Thanks a lot.
Good questions here, you’re on the right track!
Question 1: yes, the general rule of thumb is that until you are familiar with things, doing async work in the route hooks (beforeModel, model and afterModel) make it easier to think about what is going on. Eventually you may want to start bending the defaults to suit your custom UI needs, but it’s simplest to start with this rule
Questions 2-4: you’re asking several questions here about async code, so will answer here more broadly.
First off, services can do async or not but unless you call those methods from a hook (like a route hook) you are responsible for handling the asynchronous results. For instance, the Ember Data store is a service that does return data asynchronously
But if you hit cases where you do need to do async in a component, the recommended addon to help with that is Ember Concurrency: http://ember-concurrency.com/docs/introduction/
Ember Concurrency helps solve many of the async bugs and edge cases that you haven’t yet hit, but will, if you start doing async code in components. So I’d highly recommend learning more about it.
Good luck!
So I currently have a card game that when finished loads up a modal with a button to transition back to the home route. This is the action that is called when the modal's close button is clicked.
goBackHome() {
this.transitionToRoute('/games');
},
It does redirect to the requested route, but all the changes to back-end data I did still remain. I've also tried passing it the model itself
goBackHome() {
this.transitionToRoute('games');
},
Basically, it doesn't do a hard refresh of everything. What I would like is when transitionToRoute is called to reload the route as if I was inputting the exact URL into the browser myself.
Well I try to write possible way to do this, hope you can pick one and solve your problem.
you need to add this.refresh(); to either your method or in model() to force reload the model to get new data (depends on what you need)! if you want to reload the location the whole windows I mean just add location.reload();
one example should be
model(id){
var post = this.get('store').find('post', id); // Find the post from the store
post.reload(); // Force a reload
return post; // Return the fetched post NOW and the information will be updated.
}
Moreover, you can do something else in your model() look at the example :
model(params) {
return this.store.findRecord('whatever', params.id, { reload: true });
}
this { reload: true } enforces the model to get fresh data, it can be implemented with findAll as well.
ref: At the moment I'm just using the afterModel hook to force a reload, but it would be good to get the reload flag working again.
so, you can do also another way which is you can send a param to the function and get that in route and in route actions you can have this.referesh()! to reload the model. In this case, you need to add this.sendAction('actionName'); and in route actionName(){this.referesh();}
Is it possible in Yii to invoke an event handler so that it executes on each controller action call.
Basically I have a RESTful application. On each request, currently, it explicitly calls an authentication function. What I want is the authentication function calls when any request is made.
What I did
class MyController extends RestController{
public function actionDosomething(){
$this->authenticate();// I don't want this line to be put in every controller action.
}
}
Your answer is the beforeAction callback. Place this in your main Controller file.
public function beforeAction($action) {
if(in_array($action, array( /* you list of actions */ )))
{
//do your thing
}
}
Another option (in my opinion the more Yii-like approach) is to write a filter and then apply it as desired using the filters method.
It will give you even more flexibility in the future:
http://www.yiiframework.com/doc/guide/1.1/en/basics.controller#filter
I need to run some code after ember application got initialized. I don't want to invoke this code from App.ready to avoid tight coupling. It would be nice to have something like this:
App.on 'ready, -> console.log('do stuff')
But it won't work since Em.Application object is not subscribable and ready isn't really an event despite that docs said so
A simple way you can achieve this would be to extend your Application class with the Ember.Evented mixin:
App = Ember.Application.createWithMixins(Ember.Evented, {
ready: function() {
console.log('App ready');
this.trigger('appReady');
}
});
And you hook inside the ready event inside your app and trigger your custom event using this.trigger(...)
At this point you can use .on(...) to be notified when the event is triggered.
App.on('appReady', function() {
console.log('App already ready');
});
Example demo.
Hope it helps.
An other possibility may be to invoke your code from the resolve callback of the application.
App.then(function(app) {
console.log("App is resolved, so it's ready");
});
example stolen from #intuitivepixel ;) http://jsbin.com/AdOVala/66/edit
Edit/Note:
App.then() has been deprecated, see http://emberjs.com/deprecations/v1.x/#toc_code-then-code-on-ember-application:
As part of the Ember.DeferredMixin deprecation, using .then on an
Ember.Application instance itself has been deprecated.
You can use the ready hook or initializers to defer/advance readiness instead.