How to get a Boolean return value from jQuery trigger method? - events

I have a custom event that I want to fire using jQuery's trigger method:
$(wizard).trigger('validatingStepValues');
Then in the wizard's current step code, I subscribe to this event as follow:
$(wizard).bind('validatingStepValues', function (){
// Validating step's form data here; returning false on invalid state.
});
Then in my wizard, again I want to be able to stop user from going to the next step, if a false value is returned from validation process? I'd like to have something like:
$(wizard).trigger('validatingStepValues', validReturnCallback, invalidReturnCallback)

Have you considered using something like:
function wizardValidator(successCallback, failureCallback) {
return function() {
// Validating step's form data here;
if (wasValid && successCallback) {
successCallback();
}
else if (! wasValid && failureCallback) {
failureCallback();
}
return wasValid;
};
}
$(wizard).bind('validatingStepValues', wizardValidator(validReturnCallback, invalidReturnCallback));
This requires that you know the callbacks that you want to use at the time you bind the event listener. If you want to be able to use different callback functions at different times, you could define additional event types, like:
$(wizard).bind('validatingStep2Values', wizardValidator(validStep2ReturnCallback, invalidStep2ReturnCallback));
$(wizard).bind('validatingStep3Values', wizardValidator(validStep3ReturnCallback, invalidStep3ReturnCallback));
Alternately, events that you create by calling trigger() propagate up the DOM hierarchy. Returning false an event handler cancels this propagation. So you could bind your desired success callback function as an event listener on your wizard's parent node. That won't do anything to allow your failure callback to be executed, however.

Related

NGXS State documentation

I'm new to NGXS and I'm trying to fully understand the docs so I can start using it knowing what I'm doing.
There is one thing I don't understand in this code snippet from here.
export class ZooState {
constructor(private animalService: AnimalService) {}
#Action(FeedAnimals)
feedAnimals(ctx: StateContext<ZooStateModel>, action: FeedAnimals) {
return this.animalService.feed(action.animalsToFeed).pipe(tap((animalsToFeedResult) => {
const state = ctx.getState();
ctx.setState({
...state,
feedAnimals: [
...state.feedAnimals,
animalsToFeedResult,
]
});
}));
}
}
Just below this code, it says:
You might notice I returned the Observable and just did a tap. If we
return the Observable, the framework will automatically subscribe to
it for us, so we don't have to deal with that ourselves. Additionally,
if we want the stores dispatch function to be able to complete only
once the operation is completed, we need to return that so it knows
that.
The framework will subscribe to this.animalService.feed, but why?
The action, FeedAnimals, uses the injected service, AnimalService to feed the animals passed in the action's payload. Presumably the service is operates asynchronously and returns an Observable. The value of that Observable is accessed via the tap function and is used to update the ZooState state context based on completing successfully.
In order to use NGXS specifically and Angular in general, you really have to understand RxJS... here's my goto doc page for it

Intercept observables before subscription callback

I am using the following code to make get request:
makeGetReq$(url:string):Observable{
let getReqObservable;
getReqObservable = this.httpClient.get(url) //code for making get request
return getReqObservable
}
The problem is sometimes my backend might return {error:true, message} with status code 200. (I know thats weird).In that case I want to intecept getReqObservable and not allow its subscription callback to run.
image.component.ts
makeGetReq$(url:string):Observable{
let getReqObservable;
getReqObservable = this.httpClient.get(url)//code for making get request
return getReqObservable
.do((value)=>{
if(value.error){
//do not allow it to propagate further
})
})
You should propagate it further, but as an error rather than an event (i.e. do just like if your backend did the right thing and returned an error response):
makeGetReq$(url: string): Observable<Something> {
return this.httpClient.get<Something>(url).pipe(
mergeMap(value => value.error ? throwError(value) : of(value))
);
}
Otherwise, the calling method has no way to know that an error occurred, and thus can't execute the callbacks it might have registered for errors.
The easiest would probably be filter.
Filter items emitted by the source Observable by only emitting those that satisfy a specified predicate.
It would look like this:
return getReqObservable
.filter(value => !value.error)
It was pointed out, that you lose the notification completely if you just filter out the error case. There is of course the option to create a RxJS error notification with throwError, but it is also possible to just subscribe to the same source observable a second time with a different filter condition.
Be careful however to not call the backend twice, e.g. by using share.

why event listener not return false

I have some event Samevent.
For example my event have two listener;
$result = event(new Samevent());
I must be check result;
1 case
FirstListener return false;
SecondListener return false;
dd($result) = [];
2 case
FirstListener return false;
SecondListener return true;
dd($result) = [];
3 case
FirstListener return true;
SecondListener return false;
dd($result) = [true];
4 case
FirstListener return true;
SecondListener return true;
dd($result) = [true, true];
Why happens this?? How can I fix it
The reason everyone here is saying this is a mis-use of Events and Listeners is because their whole purpose is to be fired off asynchronously. When you trigger a listener, the content of that listener can't be guaranteed to finish executing before the thing that triggered it moves on. For that reason, they're not set up to offer a return.
Some more details about why you feel the desired logic must be from a Listener would be helpful, we may be able to guide you to a better pattern. For now though, I'd say you have a few options. In order of preference:
Abstract the content of your Listener's handle() method into a brand new service class. The class that you currently feel needs to access this Listener, and the Listener itself, can then reference this Service class independently of each other.
Don't fire your Listener class off an Event. Instead, instantiate it as a normal class, and then call it's handle() method directly to get your desired response.
Set config(['app.queue_driver' => 'sync']) to ensure listeners are fired off synchronously. (Make sure to change it back in a subsequent line after you trigger the listener that's intended to be synchronous, or else this could have unintended consequences for the rest of your App.) Then change your Listener so that whatever handle() does get stored in a property accessible by a new Getter method therein. This options is not advisable though. It can be done, but is so sloppy I hesitate to even suggest it. But I'm no stranger to making my code do weird things for the sake of unit-tests, so I'm not going to presume to know your circumstances.
If you need to get the result from a function, you shouldn't use the Event system to trigger that function.
You should refactor your code in one of two ways:
1) Stop using an event, and use something like a non-queued job/interaction.
$interaction = new Interaction;
$result = $interaction->handle($vars);
dd($result);
2) Pass all the variables that are required into the event, so that your listener can do any post-event processing within the listener itself.

Race condition between componentWillReceiveProps and componentDidMount

I have a component that takes some data in the props and make an ajax request with them.
var ItemList = React.createClass({
propTypes: {
filters: React.PropTypes.object.isRequired,
},
getInitialState: function() {
return {items: []};
},
componentDidMount: function() {
this.ajaxFetchItems(this.props.filters);
},
componentWillReceiveProps: function(nextProps) {
this.ajaxFetchItems(nextProps.filters);
},
ajaxFetchItems: function(filter) {
....
this.setState({items: data});
}
}
The problem is that the props are changed almost immediately, and sometimes the ajax call in componentDidMount is slightly slower than the one in componentWillReceiveProps, so the initial state is written after the first update.
How can I avoid that a slow componentDidMount will overwrite a fast componentWillReceiveProps?
There are better ways to handle the lifecycle of a react component that downloads its data?
You could put a timestamp in state for the latest update processed.
And somehow make sure that the timestamp of the original Ajax request is included in the Ajax results.
And add a shouldComponentUpdate() to check if the received results have a timestamp that is later than the timestamp in state. If not: return false, and your component will ignore the results.
By the way: componentDidMount and componentWillReceiveProps can by definition only be run in that order. I suspect that your first Ajax call takes long to return result, and your second call is fast. So you get the Ajax results back in the wrong order.
(Not due to slow react functions).
UPDATE:
Using shouldComponentUpdate is the react-way of dealing with this case: Its purpose is to allow for comparison of the new state with the old state, and based on that comparison, not rerender.
The issue is (most likely) generated by the order in which ajax responses come in:
Ajax call 1 (fired in componentDidMount in this example)
Ajax call 2 (fired in componentWillReceiveProps, trigger by parent of component)
Response from call 2 comes in
Response from call 1 comes in.
So a more generic question/ solution would be for "How to handle ajax responses coming back in the wrong order".
The timestamp (in shouldComponentUpdate) is one way to do it.
An alternative (described here) is to make the second request (in componentWillReceiveProps) abort the first ajax request.
Revisit:
After giving it some further thought (the calls in componentDidMount and componentWillReceiveProps did not feel right), a more general react-like way to approach your component would probably be as follows:
Your component's job is basically to:
receive filter via prop,
use filter to fetch list with ajax,
and render ajax reponse = list.
So it has 2 inputs:
filter (= prop)
list (= ajax response)
and only 1 output = list (which may be empty).
Workings:
The first time component receives filter as prop: it needs to send out ajax request, and render an empty list or some loading state.
all subsequent filters: component should send out a new ajax request (and kill possible outstanding old requests), and it should NOT re-render (!).
whenever it receives an ajax response, it should re-render the list (by updating state).
Setting this up with react would probably look something like this:
getInitialState() {
this.fetchAjax(this.props.filter); // initiate first ajax call here
return { list : [] }; // used to maybe display "loading.." message
}
componentWillReceiveProps(nextProps) {
this.fetchAjax(nextProps.filter); // send off ajax call to get new list with new filter
}
shouldComponentUpdate(nextProps, nextState) {
return (this.state.list != nextState.list); // only update component if there is a new list
// so when new props (filter) comes in there is NO rerender
}
render() {
createChildrenWith(this.state.list);
}
fetchAjax(filter) {
killOutStandingRequests(); // some procedure to kill old ajax requests
getListAsync…
request: filter // request new list with new filter
responseHandler: this.handleResponse // add responseHandler
}
responseHandler(data) {
this.setState({ list : data }); // put the new list in state, triggering render
}
The original timestamp in state would solve the question posted above, but I thought I'd share the revised react component as a bonus...

Can I check what values were returned in a ComboBox.DataBound event handler

I have a Kendo ComboBox which binds to a remote service. I want to check the values fetched from the server during data bound, how can I do that?
function ComboBox_DataBound(e) {
e.sender.value() // <--- this is not set yet
}
Inside the callback you can use
this.dataSource.data()

Resources