Ember Ajax Calls running in serial - ajax

Setup:
blah is my ember app
find essentially calls Ember.$.ajax(url, params, method)
the find method isn't a blocking call
Neither of the routes nor controllers have dependencies (needs) on each other
Problem:
I'm trying to figure out why the setupController (I tried activate as well) in ApplicationRoute isn't being execute until after my ajax call returns from my CowRoutes model.
Thing's I've Tried:
If I move the code from the setupController into the model of CowRoute they all run in parallel (they don't belong here at all, especially since they are header footer and I might hit a different route beside CowRoute).
I tried using Ember.RSVP.resolve on my find method, everything still works, it's just still running in serial
ApplicationRoute
blah.ApplicationRoute = Ember.Route.extend({
// setupController runs If a route handler's context changes
setupController: function () {
this.controllerFor('meta_property').set('model', blah.MetaProperty.find('meta_property'));
this.controllerFor('header').set('model', blah.User.find("user"));
}
CowRoute
blah.CowRoute = blah.Route.extend({
model: function (params) {
//this.controllerFor('meta_property').set('model', blah.MetaProperty.find('meta_property'));
//this.controllerFor('header').set('model', blah.User.find("user"));
return blah.Cow.find('cow', params);
//return Ember.RSVP.resolve(blah.Cow.find('cow', params));
}

I guess Ember tries to execute all model hooks of all Routes available af first. It waits for the model hooks to finish before executing all setupController hooks.
Why could this make sense?
Let's have a look at the interface of setupController:
setupController: function(controller, model) {
...
}
Ember is passing the model it retrieved via the model hook into the setupController hook. This is why it has to wait.
But why does it wait for your CowRoutes model hook before running setupController on your ApplicationRoute?
I guess this is because, you might call controllerFor(name) inside setupController and Ember wants all models "to be in place".
But i think this behaviour should not hurt too much, since the model hook is just executed when the App is entered via URL for deserialization of parameters.
Note: This answer is just a guess from my side, but it seems to make sense to me. At least it should be in the right direction :-)

According to convention, If you have a model that is not in the url and across multiple routes, its ideal to put those in the application route ;)

Related

How to overwrite global event handler in nested Vue component, and later use the previous one?

I am working in Vue and also i use VueRouter, VueX and VueWebsocket. My App has component called App which holds all other components inside itself. Also I have websocket event which is set globally like this:
this.$options.sockets.onmessage = (websocket) => { /* sth1 */ }
When it gets any data from websocket, sth1 is called. it works like charm. However deep inside App component is another component, let's call it InputComponent. It may be included in App or not becaue it is single page aplication and some parts do include InputComponent, and some do not. Inside InputComponent there is also:
this.$options.sockets.onmessage = (websocket) => { /* sth2 */ }
And of course it overwrites function on message so sth1 will never be executed if InputComponent is nested by App component. It is quite obvious. However if i remove (in next SPA page), and InputComponent disappears i still have my onmessage event overwritten which i would like to have in original version.
I could ofcourse make some kind of merging functionalities of sth1 and sth2 in App component or InputComponent but it is repeating myself.
Here comes the question - is there a way to return original version of onmessage event without reloading whole App Component? In other words: can i have temporary overwritten function and then come back to its functionalities? Something like extending an eent with new functionalities of sth2.
I hope you get the idea!
K.
The general way to do that would be to use addEventListener and removeEventListener. So in the input component
created() {
this.$options.sockets.addEventListener('message', handleMessage);
},
destroyed() {
this.$options.sockets.removeEventListener('message', handleMessage);
}
Note that this approach doesn't prevent the original handler from also receiving the events. Without knowing more about the app architecture, it's hard to suggest the best way to avoid this behavior, but perhaps you can set a messageHandled flag on the event in the component's handler; then check that flag in the parent.

Redux - Previous values for props/state showing briefly before new values loaded

I am setting up my React project with Redux for the first time, and am running into an issue.
I have a basic container, mapStateToProps, action creator, and reducer in place, but I'm having this issue where when I load a certain page, the previous prop values are getting loaded to the page before the correct values are fetched. It makes sense that this is happening, but I was wondering if there was a way to get around this so that upon loading this component / container that the values would get cleared. (Or if it'd just be better to use React state instead of Redux state for this specific use case? The rest of the pages make sense to use Redux, but this is the only case where this becomes an issue)
Say I have a page that shows some state of some item: somePage.com/items/
The component and container are set up like this (skeletal for the sake of example):
class SomeComponent extends React.Component<......> {
constructor(props) {
super(props);
props.dispatch(fetchItemDetail(params));
}
render() {
// use the stuff in props to display item's info
}
}
function mapStateToProps(state) {
return {
someItemDetail: state.someItemDetail.X;
someOtherInfo: state.someDetail.Y;
}
}
export const ItemDetailContainer = connect(mapStateToProps)(SomeComponent)
The action creator involves calling an API and returning the payload, and the reducer is just a standard reducer that sticks the result of the API call into the state.
Basically, this "works", but if I navigate from going into SomeComponent with a parameter for ItemX, and click a link to go to SomeComponent for ItemY, ItemX's information will show until the call to fetch ItemY's info completes, then ItemY's info will appear.
What's the recommended approach for handling this issue? It looks like I can't just clear the props upon construction because they are readonly. Any thoughts?
Self-answer:
I got something to work. Basically, I ended up just creating an action creator, clearItemDetail w/ CLEAR_ITEM_DETAIL type. When the reducer sees actions with CLEAR_ITEM_DETAIL, they would then "clear" that part of the state. (I had multiple things to clear, so my actions and reducers were a little more complicated than this though.)
I dispatched the clearItemDetail() action creator inside the componentWillUnmount() lifecycle method of the component, and it seems to be working now.
Not sure if this is the best route though.
It looks like fetchItemDetail is an asynchronous call. That being so, write a reducer for fetchItemDetail to clear ItemY's data. The reducer can coexist with the middleware to handle the asynchronous call.
case FETCH_ITEM_DETAIL:
return Object.assign({}, state, {ItemY: null});
break;
You can handle the null value in ItemY in your component to not show any data. Then, upon completion of the asynchronous call, assign the returned value (this sounds like it's already done as the ItemY data does appear when the call is complete):
case FETCH_ITEM_COMPLETE:
return Object.assign({}, state, {ItemY: [your item y data]});
break;

What is the best place to put onEnter, onExit callback functionality?

I am creating my first project that uses ui-router.
My project has about 10 views, each with their own controller and state. I am trying to modularise/encapsulate/decouple as best as possible but I am having trouble working out where to put the onExit and onEnter state callbacks.
The first option is to put it in app.js which is currently defining all of my states, however I feel that this would not be a good place as it could cause this file to blow up and become hard to read as more states are introduced and the logic gets more complex.
The second option I looked into was to put it into a controller (I have one for each state), however from researching it doesn't seem to be best practice to do this.
The third option is to create a service that is resolved, however with this option I would end up with either a giant service full of state change functions for each of the states (not decoupled) or an additional service per state which would contain the state change functionality, and I worry that would increase project complexity.
What is the standard way to achieve this?
Are there any other options that I am missing?
Our strategy for this has been to disregard the onEnter and onExit on the state object, because as you are discovering, they feel like they are in the wrong place in terms of separation of concerns (app.js).
For onEnter: we handle setup in an activate() function in each controller, which we manually execute inside the controller. This happens to also match the callback that will get executed in Angular 2.0, which was not an accident ;).
function activate() {
// your setup code here
}
// execute it. this line can be removed in Angular 2.0
activate();
For onExit: We rarely need an exit callback, but when we do, we listen for the $scope $destroy event.
$scope.$on("$destroy", function() {
if (timer) {
$timeout.cancel(timer);
}
});

Routing Conventions in Can.js

So I’m looking to make some routes within my super cool can.js application. Aiming for something like this…
#!claims ClaimsController - lists claims
#!claims/:id ClaimController - views a single claim
#!claims/new ClaimController - creates a new claim
#!claims/:id/pdf - do nothing, the ClaimController will handle it
#!admin AdminController - loads my Administrative panel with menu
#!admin/users - do nothing, the AdminController will handle it
#!admin/settings - do nothing, the AdminController will handle it
So how might we do this?
“claims route”: function() { load('ClaimsController'); },
“claims/:id route”: function() { load('ClaimController'); },
“admin”: function() { load(‘AdminController’); },
Cool beans, we’re off. So what if someone sends a link to someone like...
http://myapp#!claims/1/pdf
Nothing happens! Ok, well let’s add the route.
“claims/:id/pdf route”: function() { load('ClaimController'); },
Great. Now that link works. Here, the router’s job is only to load the controller. The controller will recognize that the pdf action is wanted, and show the correct view.
So pretend I’ve loaded up a claim claims/:id and I edit one or two things. Then I click the Print Preview button to view the PDF and change my route to claims/:id/pdf.
What should happen… the Claim Controller is watching the route and shows the pdf view.
What actually happens… the router sees the change, matches the claims/:id/pdf route we added, and reloads the Claim Controller, displaying a fresh version of the claim pulled from the server/cache, losing my changes.
To try and define the problem, I need the router to identify when the route changes, what controller the route belongs to, and if the controller is already loaded, ignore it. But this is hard!
claims //
claims/:id // different controllers!
claims/:id //
claims/:id/pdf // same controller!
We could just bind on the "controller" change. So defining routes like can.route(':controller') and binding on :controller.
{can.route} controller
// or
can.route.bind('controller', function() {...})
But clicking on a claim (changing from ClaimsController to ClaimController) won't trigger, as the first token claim is the same in both cases.
Is there a convention I can lean on? Should I be specifying every single route in the app and checking if the controller is loaded? Are my preferred route urls just not working?
The following is how I setup routing in complex CanJS applications. You can see an example of this here.
First, do not use can.Control routes. It's an anti-pattern and will be removed in 3.0 for something like the ideas in this issue.
Instead you setup a routing app module that imports and sets up modules by convention similar to this which is used here.
I will explain how to setup a routing app module in a moment. But first, it's important to understand how can.route is different from how you are probably used to thinking of routing. Its difference makes it difficult to understand at first, but once you get it; you'll hopefully see how powerful and perfect it is for client-side routing.
Instead of thinking of urls, think of can.route's data. What is in can.route.attr(). For example, your URLs seem to have data like:
page - the primary area someone is dealing with
subpage - an optional secondary area within the page
id - the id of a type
For example, admin/users might want can.route.attr() to return:
{page: "admin", subpage: "users"}
And, claims/5 might translate into:
{page: "claims", id: "5"}
When I start building an application, I only use urls that look like #!page=admin&subpage=users and ignore the pretty routing until later. I build an application around state first and foremost.
Once I have the mental picture of the can.route.attr() data that encapsulates my application's state, I build a routing app module that listens to changes in can.route and sets up the right controls or components. Yours might look like:
can.route.bind("change", throttle(function(){
if( can.route.attr("page") == "admin" ) {
load("AdminController")
} else if(can.route.attr("page") === "claims" && can.route.attr("id") {
load("ClaimController")
} else if ( ... ) {
...
} else {
// by convention, load a controller for whatever page is
load(can.capitalize(can.route.attr("page")+"Controller")
}
}) );
Finally, after setting all of that up, I make my pretty routes map to my expected can.route.attr() values:
can.route(":page"); // for #!claims, #!admin
can.route("claims/new", {page: "claims", subpage: "new"});
can.route("claims/:id", {page: "claims"});
can.route("admin/:subpage",{page: "admin"});
By doing it this way, you keep your routes independent of rest of the application. Everything simply listens to changes in can.route's attributes. All your routing rules are maintained in one place.

C# lock keyword, I think I'm using this wrong

I recently had a problem with multiple form posting in an ASP.NET MVC application. The situation was basically, if someone intentionally hammered the submit button, they could force data to be posted multiple times despite validation logic (both server and client side) that was intended to prohibit this. This occurred because their posts would go through before the Transaction.Commit() method could run on the initial request (this is all done in nHibernate)
The MVC ActionMethod looked kind of like this..
public ActionResult Create(ViewModelObject model)
{
if(ModelState.IsValid)
{
// ...
var member = membershipRepository.GetMember(User.Identity.Name);
// do stuff with member
// update member
}
}
There were a lot of solutions proposed, but I found the C# lock statement, and gave it a try, so I altered my code to look like this...
public ActionResult Create(ViewModelObject model)
{
if(ModelState.IsValid)
{
// ...
var member = membershipRepository.GetMember(User.Identity.Name);
lock(member) {
// do stuff with member
// update member
}
}
}
It worked! None of my testers can reproduce the bug, anymore! We've been hammering away at it for over a day and no one can find any flaw. But I'm not all that experienced with this keyword. I looked it up again to get clarification...
The lock keyword marks a statement block as a critical section by obtaining the mutual-exclusion lock for a given object, executing a statement, and then releasing the lock
Okay, that makes sense. Here is my question.
This was too easy
This solution seemed simple, straightforward, clear, efficient, and clean. It was way too simple. I know better than to think something that complicated has that simple a solution. So I wanted to ask more experienced programmers ...
Is there something bad going on I should be aware of?
No it's not that easy. Locking only works if the same instance is used.
This will not work:
public IActionResult Submit(MyModel model)
{
lock (model)
{
//will not block since each post generates it's own instance
}
}
Your example could work. It all depends on if second-level caching is enabled in nhibernate (and thus returning the same user instance). Note that it will not prevent anything from being posted to the database, just that each post will be saved in sequence.
Update
Another solution would be to add return false; to the submit button when it's being pressed. it will prevent the button from submitting the form multiple times.
Here is a jquery script that will fix the problem for you (it will go through all submit buttons and make sure that they will only submit once)
$(document).ready(function(){
$(':submit').click(function() {
var $this = $(this);
if ($this.hasClass('clicked')) {
alert('You have already clicked on submit, please be patient..');
return false;
}
$this.addClass('clicked');
});
});
Add it do you layout or to a javascript file.
Update2
Note that the jquery code works in most cases, but remember that any user with a little bit of programming knowledge can use for instance HttpWebRequest to spam POSTs to your web server. It's not likely, but it could happen. The point I'm making is that you should not rely on client side code to handle problems since they can be circumvented.
Yeah, it's that easy, but - there may be a performance hit. Remember that a Monitor lock restricts that code to be run by only one thread at a time. There is a new thread for each HTTP Request, so that means only one of those requests at any given time can access that code. If it's a long running procedure, or a lot of people are trying to access that part of the site at the same time - you might start to sluggish responses.
It's that easy, but be careful what object you lock on. It should be the same one for all the threads - for example, it could be a static object.
lock is syntactic sugar for a Monitor, so there is quite a bit going on under the cover.
Also, you should keep an eye out for deadlocks - they can happen when you lock on two or more objects.

Resources