Trigger multi-events - triggers

Can I trigger multi events in trigger() or chain them in JQuery!? E.g:
$(element).trigger('event1 event2 event3');
or
$(element).trigger('event1').trigger('event2');
or
$(element).trigger('event1');
$(element).trigger('event2');

As other answers note, the best built-in method is:
$(element).trigger('event1').trigger('event2');
However, I find that if you're doing this all over the place, a simple plugin cleans it up quite nicely, allowing the space-separated syntax (like other jQuery methods). Here's a quick example of such a plugin:
$.fn.triggerAll = function(events) {
if(!events) return this; //don't blow up if .triggerAll() without params
var self = this; //keep a reference
$.each(events.split(" "), function(i, e) { self.trigger(e); });
return this;
};
Then you can call it with space-separated event names, like this:
$(element).triggerAll('event1 event2 event3');
You can test it out here

$(element).trigger('event1 event2 event3');
is not supported.
(element).trigger('event1').trigger('event2');
is optimal over
$(element).trigger('event1');
$(element).trigger('event2');
as you are not rebuilding the jQuery object containing $(element) each time you trigger an event.

Related

Are getter functions necessary for Protractor element locators

When using PageObjects for Protractor e2e tests, should you use getter functions for the element locator variables instead of having variables?
example:
public loginButton: ElementFinder = $('#login-submit');
public loginUsername: ElementFinder = $('#login-username');
Or should you use a getter function in the Page Object like this:
public get loginButton(): ElementFinder {
return $('#login-submit');
}
public get loginUsername(): ElementFinder {
return $('#login-username');
}
Is one approach better than another?
No getters needed, since protractor ElementFinder and ElementArrayFinder objects are lazy - no any searching for this element will be done until you will try to call some methods on them. Actually thats also a reason why you don't need to use await for protractor element search methods:
const button = $('button') // no await needed, no getter needed
console.log('Element is not yet tried to be searched on the page')
await button.click() // now we are sending 2 commands one by one - find element and second - do a click on found element.
http://www.protractortest.org/#/api?view=ElementFinder
ElementFinder can be used to build a chain of locators that is used to find an element. An ElementFinder does not actually attempt to find the element until an action is called, which means they can be set up in helper files before the page is available.
It's fine to use either but if you're going to transform or do something else to your element, then the getter function would be better in my opinion since that's the reason why we utilize mutators in the first place.
I'm not really sure which method is more convenient, if there is one.
I've been using protractor for a bit longer than 1 year now, and I always stored locators in variables.
What I'd normally do is:
const button = element(by.buttonText('Button'));
Then I'd create a function for interacting with the element:
const EC = protractor.ExpectedConditions;
const clickElement = async (element) => {
await browser.wait(EC.elementToBeClickable(element));
await element.click();
};
Finally, use it:
await clickElement(button);
Of course I store the locators and functions in a page object, and invoking/calling them in the spec file. It's been working great so far.

Multicast Delegates - C++

I would like to receive a multicast event from the LeapMotion plugin in C++. From their documentation, they mention the following things:
> On Hand Grabbed Event called when a leap hand grab gesture is
> detected. Signature: const FLeapHandData&, Hand, see FLeapHandData
>
> FLeapHandSignature OnHandGrabbed;
So in my .cpp file I added the following:
ALeapMotionGesture::ALeapMotionGesture()
{
PrimaryActorTick.bCanEverTick = true;
Leap = CreateDefaultSubobject<ULeapComponent>(TEXT("Leap"));
}
void ALeapMotionGesture::BeginPlay()
{
Super::BeginPlay();
if (Leap != nullptr) {
FScriptDelegate Delegate;
Delegate.BindUFunction(this, FName("HandGrabbed"));
Leap->OnHandGrabbed.Add(Delegate);
}
}
void ALeapMotionGesture::HandGrabbed(const FLeapHandData& Hand) {
UE_LOG(LogTemp, Warning, TEXT("Hand Grabbed"));
}
As it is the first time I'm using delegates in Unreal/C++, I would like to know how I could make it work?
It compiles fine however I do not receive any events.
Add UFUNCTION() on your function HandGrabbed
Short Answer
Replace:
void ALeapMotionGesture::BeginPlay()
{
Super::BeginPlay();
if (Leap != nullptr) {
FScriptDelegate Delegate;
Delegate.BindUFunction(this, FName("HandGrabbed"));
Leap->OnHandGrabbed.Add(Delegate);
}
}
with:
void ALeapMotionGesture::BeginPlay()
{
Super::BeginPlay();
if (Leap != nullptr) {
Leap->OnHandGrabbed.AddDynamic(this, &ALeapMotionGesture::HandGrabbed);
}
}
Long Answer
ULeapComponent::OnHandGrabbed is a FLeapHandSignature which is declared with DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam.
The LeapMotion README says to consult the Multi-cast documentation, but they are using dynamic delegates, so you actually need to read the Dynamic Delegates documentation. There you will see you should use the AddDynamic helper macro which generates the function name string for you.
Dynamic Delegates make use of helper macros that take care of generating the function name string for you.
From the Dynamic Delegates doc:
Dynamic Delegate Binding
BindDynamic( UserObject, FuncName )
Helper macro for calling BindDynamic() on dynamic delegates.
Automatically generates the function name string.
AddDynamic( UserObject, FuncName )
Helper macro for calling AddDynamic() on dynamic multi-cast delegates.
Automatically generates the function name string.
RemoveDynamic( UserObject, FuncName )
Helper macro for calling RemoveDynamic() on dynamic multi-cast
delegates. Automatically generates the function name string.
Side Note
Dynamic delegates are serialized, which sometimes results in unexpected behavior. For example, you can have delegate functions being called even though your code is no longer calling AddDynamic (because a serialized/saved actor serialized the results of your old code) or you might call AddDynamic even though the deserialization process already did that for you. To be safe, you probably should call RemoveDynamic before AddDynamic. Here's a snippet from FoliageComponent.cpp:
// Ensure delegate is bound (just once)
CapsuleComponent->OnComponentBeginOverlap.RemoveDynamic(this, &AInteractiveFoliageActor::CapsuleTouched);
CapsuleComponent->OnComponentBeginOverlap.AddDynamic(this, &AInteractiveFoliageActor::CapsuleTouched);

Get newly created id of a record before redirecting page

I would like to retrieve the id of a newly created record using javascript when I click on save button and just before redirecting page.
Do you have any idea please ?
Thank you !
One way to do this in Sugar 7 would be by overriding the CreateView.
Here an example of a CustomCreateView that outputs the new id in an alert-message after a new Account was successfully created, but before Sugar gets to react to the created record.
custom/modules/Accounts/clients/base/views/create/create.js:
({
extendsFrom: 'CreateView',
// This initialize function override does nothing except log to console,
// so that you can see that your custom view has been loaded.
// You can remove this function entirely. Sugar will default to CreateView's initialize then.
initialize: function(options) {
this._super('initialize', [options]);
console.log('Custom create view initialized.');
},
// saveModel is the function used to save the new record, let's override it.
// Parameters 'success' and 'error' are functions/callbacks.
// (based on clients/base/views/create/create.js)
saveModel: function(success, error) {
// Let's inject our own code into the success callback.
var custom_success = function() {
// Execute our custom code and forward all callback arguments, in case you want to use them.
this.customCodeOnCreate(arguments)
// Execute the original callback (which will show the message and redirect etc.)
success(arguments);
};
// Make sure that the "this" variable will be set to _this_ view when our custom function is called via callback.
custom_success = _.bind(custom_success , this);
// Let's call the original saveModel with our custom callback.
this._super('saveModel', [custom_success, error]);
},
// our custom code
customCodeOnCreate: function() {
console.log('customCodeOnCreate() called with these arguments:', arguments);
// Retrieve the id of the model.
var new_id = this.model.get('id');
// do something with id
if (!_.isEmpty(new_id)) {
alert('new id: ' + new_id);
}
}
})
I tested this with the Accounts module of Sugar 7.7.2.1, but it should be possible to implement this for all other sidecar modules within Sugar.
However, this will not work for modules in backward-compatibility mode (those with #bwc in their URL).
Note: If the module in question already has its own Base<ModuleName>CreateView, you probably should extend from <ModuleName>CreateView (no Base) instead of from the default CreateView.
Be aware that this code has a small chance of breaking during Sugar upgrades, e.g. if the default CreateView code receives changes in the saveModel function definition.
Also, if you want to do some further reading on extending views, there is an SugarCRM dev blog post about this topic: https://developer.sugarcrm.com/2014/05/28/extending-view-javascript-in-sugarcrm-7/
I resolved this by using logic hook (after save), for your information, I am using Sugar 6.5 no matter the version of suitecrm.
Thank you !

How do I use findOrCreateEach in waterline/sailsjs?

I been looking around on the sails site and was lead to the waterline page. I am curious to how I can use the findOrCreateEach method. Specifically, number of arguments, what it will return, and how it will benefit me using it? I been searching, around and going to have to dive into the source code. I figure I ask here while I look.
Method without bluebird promises
Model.findOrCreateEach(/* What Goes Here */).exec(/* What Returns Here */);
With bluebird promises
Model.findOrCreateEach(/* What Goes Here */).then(/* What Returns Here */);
findOrCreateEach is deprecated; that's why it's not in the documentation. The best way to replicate the functionality is by using .findOrCreate() in an asynchronous loop, for example with async.map:
// Example: find or create users with certain names
var names = ["scott", "mike", "cody"];
async.map(names, function(name, cb) {
// If there is a user with the specified name, return it,
// otherwise create one
User.findOrCreate({name: name}, {name: name}).exec(cb);
},
function done(err, users) {
if (err) { <handle error and return> }
<users now contains User instances with the specified names>
});

Handling errors in an observable sequence using Rx

Is there a way to have an observable sequence to resume execution with the next element in the sequence if an error occurs?
From this post it looks like you need to specify a new observable sequence in Catch() to resume execution, but what if you needed to just continue processing with the next element in the sequence instead? Is there a way to achieve this?
UPDATE:
The scenario is as follows:
I have a bunch of elements that I need to process. The processing is made up of a bunch of steps. I have
decomposed the steps into tasks that I would like to compose.
I followed the guidelines for ToObservable() posted here
to convert by tasks to an observables for composition.
so basically I'm doing somethng like so -
foreach(element in collection)
{
var result = from aResult in DoAAsync(element).ToObservable()
from bResult in DoBAsync(aResult).ToObservable()
from cResult in DoCAsync(bResult).ToObservable()
select cResult;
result.subscribe( register on next and error handlers here)
}
or I could something like this:
var result =
from element in collection.ToObservable()
from aResult in DoAAsync(element).ToObservable()
from bResult in DoBAsync(aResult).ToObservable()
from cResult in DoCAsync(bResult).ToObservable()
select cResult;
What is the best way here to continue processing other elements even if let's say the processing of
one of the elements throws an exception. I would like to be able to log the error and move on ideally.
Both James & Richard made some good points, but I don't think they have given you the best method for solving your problem.
James suggested using .Catch(Observable.Never<Unit>()). He was wrong when he said that "will ... allow the stream to continue" because once you hit an exception the stream must end - that is what Richard pointed out when he mentioned the contract between observers and observables.
Also, using Never in this way will cause your observables to never complete.
The short answer is that .Catch(Observable.Empty<Unit>()) is the correct way to change a sequence from one that ends with an error to one that ends with completion.
You've hit on the right idea of using SelectMany to process each value of the source collection so that you can catch each exception, but you're left with a couple of issues.
You're using tasks (TPL) just to turn a function call into an observable. This forces your observable to use task pool threads which means that the SelectMany statement will likely produce values in a non-deterministic order.
Also you hide the actual calls to process your data making refactoring and maintenance harder.
I think you're better off creating an extension method that allows the exceptions to be skipped. Here it is:
public static IObservable<R> SelectAndSkipOnException<T, R>(
this IObservable<T> source, Func<T, R> selector)
{
return
source
.Select(t =>
Observable.Start(() => selector(t)).Catch(Observable.Empty<R>()))
.Merge();
}
With this method you can now simply do this:
var result =
collection.ToObservable()
.SelectAndSkipOnException(t =>
{
var a = DoA(t);
var b = DoB(a);
var c = DoC(b);
return c;
});
This code is much simpler, but it hides the exception(s). If you want to hang on to the exceptions while letting your sequence continue then you need to do some extra funkiness. Adding a couple of overloads to the Materialize extension method works to keep the errors.
public static IObservable<Notification<R>> Materialize<T, R>(
this IObservable<T> source, Func<T, R> selector)
{
return source.Select(t => Notification.CreateOnNext(t)).Materialize(selector);
}
public static IObservable<Notification<R>> Materialize<T, R>(
this IObservable<Notification<T>> source, Func<T, R> selector)
{
Func<Notification<T>, Notification<R>> f = nt =>
{
if (nt.Kind == NotificationKind.OnNext)
{
try
{
return Notification.CreateOnNext<R>(selector(nt.Value));
}
catch (Exception ex)
{
ex.Data["Value"] = nt.Value;
ex.Data["Selector"] = selector;
return Notification.CreateOnError<R>(ex);
}
}
else
{
if (nt.Kind == NotificationKind.OnError)
{
return Notification.CreateOnError<R>(nt.Exception);
}
else
{
return Notification.CreateOnCompleted<R>();
}
}
};
return source.Select(nt => f(nt));
}
These methods allow you to write this:
var result =
collection
.ToObservable()
.Materialize(t =>
{
var a = DoA(t);
var b = DoB(a);
var c = DoC(b);
return c;
})
.Do(nt =>
{
if (nt.Kind == NotificationKind.OnError)
{
/* Process the error in `nt.Exception` */
}
})
.Where(nt => nt.Kind != NotificationKind.OnError)
.Dematerialize();
You can even chain these Materialize methods and use ex.Data["Value"] & ex.Data["Selector"] to get the value and selector function that threw the error out.
I hope this helps.
The contract between IObservable and IObserver is OnNext*(OnCompelted|OnError)? which is upheld by all operators, even if not by the source.
Your only choice is to re-subscribe to the source using Retry, but if the source returns the IObservable instance for every description you won't see any new values.
Could you supply more information on your scenario? Maybe there is another way of looking at it.
Edit: Based on your updated feedback, it sounds like you just need Catch:
var result =
from element in collection.ToObservable()
from aResult in DoAAsync(element).ToObservable().Log().Catch(Observable.Empty<TA>())
from bResult in DoBAsync(aResult).ToObservable().Log().Catch(Observable.Empty<TB>())
from cResult in DoCAsync(bResult).ToObservable().Log().Catch(Observable.Empty<TC>())
select cResult;
This replaces an error with an Empty which would not trigger the next sequence (since it uses SelectMany under the hood.