"Routes and controllers that handle actions must place action handlers inside an actions hash. Even if a route has a method with the same name as the actions, it will not be triggered unless it is inside an actions hash. In the case of a controller, while there is deprecated support for triggering a method directly on the controller, it is strongly recommended that you put your action handling methods inside an actions hash for forward compatibility."
That is from the ember documentation, it sounds like I should put my actions inside the actions hash within a controller, but after I put the action inside the hash, my controller complains that Uncaught Error: Nothing handled the event 'submit'.
//this works
App.StartController = Ember.Controller.extend({
submit:function(){
alert(1);
}
});
// this complains Uncaught Error: Nothing handled the event 'submit'.
App.StartController = Ember.Controller.extend({
actions:{
submit:function(){
alert(1);
}
}
});
BTW, I am using v1.0.0rc
Just to reference #mavilein's comment, I updated my ember libraries and it's working now.
Related
I want to perform an action based to the result of an asynchronous NGXS action.
In a Angular frontend app I'm using NGXS for state management. Some of the actions involve talking to a backend via REST calls. Those actions are implemented as asynchronous actions, with the reducer functions in my state classes returning an Observable.
What I'm looking for is a way to get hands on the result of the backend call, to be able to perform some action.
One use case I'm trying to implement is navigation to just created objects: Business objects are created in the frontend (Angular) app with a couple of domain properties. They get persisted in the backend, and as a result an ID for this object is created and returned to the frontend, and incorporated into the NGXS store. As a direct response to this, I'd like to navigate to a detail view for the new object. To do so, I need
(a) the information that the call has been returned successful, and
(b) the answer from the backend (the ID in this case).
Another slightly more complicated use case is the assignment of a number of tags to an business object. The tags are entities by themselfes, and have an ID each. In the UI, the user can either pick existing or add new tags. Either way, multiple tags can be added in a single step in the UI, which means I have to
call the backend for each new tag to create the ID
after all missing tags are created, update the business object with the list of tag IDs
In general, there are use cases in the frontend that depend on the result of a backend call, and there is no clean way to find this result in the store (although it's in there)
I know I can subscribe to the Observable returned from the store's dispatch method (as shown in asynchronous actions).
I also know about action handlers. In both cases I can attach code to the event of an action finished, but neither option enables me to get the result of the backend call. In the fist case, the Observable carries the whole store, while in the latter case I get the original Action, which is unfortunately missing the essential information (the ID).
The part you're missing here are selectors. Dispatching actions is not supposed to give you back a result. The only purpose of the Observable returned by store.dispatch() is to tell you when the action's handlers are done.
To get to the data returned by your calls to the backend, you have to patch the state inside your action handler. And then, outside of your state, you can access the data using store.select() or store.selectSnapshot() depending on what you need. Your state class should look somewhat like this (untested):
#State()
export class SampleState {
#Selector(SampleState)
sampleSelector(state) {
return state.sampleObject;
}
#Action(SampleAction)
sampleAction(ctx: StateContext<any>, action: sampleAction) {
return sampleBackendCall(/* ... */).pipe(
tap((result) => {
ctx.patchState({ sampleObject: result });
})
);
}
}
Now you can access this result where ever you need using the Store. For the use case of navigating to an element after its creation, you can combine a subscription to store.dispatch() with a store.selectSnapshot() like this:
store.dispatch(new SampleAction()).subscribe(() => {
navigateTo(store.selectSnapshot(SampleState.sampleSelector));
});
Note that in this easy case a selectSnapshot is perfectly fine, as we only want to get the value we just finished writing into the state. In most cases though, you will want to use store.select() or the #Select() decorator because they return Observables which enable you to also correctly display changes in your state.
That said, I'd like to add that if saving data inside the state is not necessary for you at all, then probably NGXS is the wrong library for you in the first place and you could as well just use an ordinary angular service directly returning the result of the backend call, like suggested in the comments.
I'm not used to Vue components. My second problem is, I wanted to pass data from laravel blade, to vuejs component in the right way. Because what I did is I store it to props, then pass the props into the data property, like this:
//ticket blade
<ticket-create :menu-categories-prop="{{ json_encode($menuCategories) }}"></ticket-create>
//ticket component
export default {
props: ['menuCategoriesProp'],
created(){
this.menuCategories = this.menuCategoriesProp;
},
data() {
return {
menuCategories: [],
}
}
}
now I have menuCategoriesProp and menuCategories data, which is kinda redundant. Am I doing it wrong?
It is not a redundancy problem, it's a logic problem. You should not pass ANY variable from blade to view in my opinion. You should do something like this:
Your controller (maybe from the index method) checks if the request wants a JSON response, if not returns the view, otherwise the collection as a JSON response (go on to understand why).
When the view is loaded, VueJs loads the component and (this is how I do it) within the mounted method you make an Ajax call (maybe with axios) to your controller which will return the collection
In this way you have an asynchronous request management, that will allow you to refresh the data, and avoid to reload the page each time.
As I wrote before, I would avoid as much as possible to pass properties from blade to vue, unless they're context variables like user preferences or system settings.
Your code is ok. You can get categories over ajax. In your case, it is not recommended to use ajax.
I have ajax controler to store actions that are called through the AJAX from JS.
Here in every action I validate if request is made by AJAX and no other:
if (!$request->isXmlHttpRequest()) {
return new JsonResponse(array('message' => 'You can access this only using Ajax!'), 400);
}
Now the problem is that not every ajax controller action should be called by everyone, but rather depending on a role of the logged in user.
The request to action is made by AJAX from JS, but since actions are in controller I am still able to get logged in user object by $this->getUser() and to check if user has acceptable ROLE to execute the controller action by isGranted().
Example:
if (!$authorizationChecker->isGranted('ROLE_ADMIN')) {
return new JsonResponse(array('message' => 'This can be performed only by admin!'), 400);
}
Should I check ROLES from inside controller in every action or try to configure access_control for ajax routes in security.yml?
I have no idea what is the big difference between these two approaches, but would like to know which one would be more practical and could keep my ajax actions more secure.
Depends on the number of AJAX Controllers you have. If you have so many controllers those are to be allowed only for a certain role, access_control in security.yml is a good choice. Else you can have the condition in each controller.
For dynamic permission layer, where permission to be decided based on subject attribute(the viewing content), You might want to use voter.
I'd like to know what the success and error do in the Ember.js RESTAdapter's ajax function.
hash.success = function(json) {
Ember.run(null, resolve, json);
};
hash.error = function(jqXHR, textStatus, errorThrown) {
Ember.run(null, reject, jqXHR);
};
I know hash is the data sent through AJAX, but what role do success and error play? I assume they'd be run based on a successful or erroneous AJAX response, right? They're set before the AJAX is called, as callbacks? How do they work?
but what role do success and error play? I assume they'd be run based on a successful or erroneous AJAX response, right?
Right, since ember uses jQuery under the hood the functions mentioned are just plain jQuery methods.
They're set before the AJAX is called, as callbacks? How do they work?
As for the functions itself, see this info taken from the jQuery official docs:
error callback option is invoked, if the request fails. It receives the jqXHR, a string indicating the error type, and an exception object if applicable. Some built-in errors will provide a string as the exception object: "abort", "timeout", "No Transport".
success callback option is invoked, if the request succeeds. It receives the returned data, a string containing the success code, and the jqXHR object.
I should also mention that the success callback is in recently jQuery version being replaced with done and is marked as deprecated as noted here:
Deprecation Notice: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks are deprecated as of jQuery 1.8. To prepare your code for their eventual removal, use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.
But don't worry, because I guess until jQuery removes this methods completely the ember team has surely catched up with the new callback versions.
And finally if you where wondering what the call to Ember.run does you can have a look here. But basically it ensures that the passed target and method are run inside of a RunLoop, ensuring also any deferred actions like bindings and views updates, this are flushed at the end. This SO answer on the Runloop is also very informative.
Hope it helps.
This is a partially hypothetical question, as I don't actually need to do this at the moment. I'm just anticipating that I might.
My MVC3 app has a page that has a partial view that is refreshed using MVC3 Ajax and AjaxHelper.BeginForm(). It all works nicely.
But, it's possible for the action that generates the partial view to realize that rather than see a refresh of the partial view, the user needs to be sent to a completely different page. In other words, rather than returning a PartialViewResult, the action method needs to return a RedirectResult or a regular View.
This, as you no doubt know, won't work: attempts to return a RedirectResult when the signature calls for a PartialViewResult won't compile.
So how can this be accomplished? Let's say for the sake of argument that the necessary decision can only be made server-side and only after the information in the partial view is posted back to the server.
First, define your method to return an ActionResult, which will allow you to return either a PartialViewResult or RedirectResult, as needed.
Second, supply an OnFailure callback function in your BeginForm() method call. If the result of the AJAX call is not an HTTP 200, the OnFailure callback will be run, which you can then use to parse the redirect response and perform the redirect.