Set execution order of event-handlers of click event in jQuery? - event-handling

I am using jQuery 1.9.1.
Suppose i have a button with id="clickMe"
My jQuery code is:
$('#clickMe').click(function(event)
{
eventHandler1();//do something
eventHandler2();//use output from eventHandler1() and do something
}
Now, i want "eventHandler2" to be executed at last so that i could use the output of "eventHandler1". Is there any way to do this manually and not just the way i have put the handlers inside the click event?
One more thing, "eventHandler1()" and "eventHandler2()" are present in different .js files and thus the requirement.

jQuery.when() provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events.
For example, when the Deferreds are jQuery.ajax() requests, the arguments will be the jqXHR objects for the requests, in the order they were given in the argument list.
$.when(eventHandler1).then(eventHandler2).done(function(){
alert('done.');
});

So can even use GLOBAL variable to store eventHandler1 output and access that inside eventHandler2
Example
var someVar;
function eventHandler1()
{
// process
someVar = some value from process
return someVar;
}
function eventHandler2()
{
alert(someVar);
}
Response to OP comment
as you have asked about execute handler in queue you can use Jai answer.
you can use .when .then and .done as below.
$.when(eventHandler1).then(eventHandler2).done(function(){
//process code
});

Related

Is there a fix to highlight subsequent DOM changes using a Chrome Extension that currently only reads source code (+highlights keywords) on page load? [duplicate]

Essentially I want to have a script execute when the contents of a DIV change. Since the scripts are separate (content script in the Chrome extension & webpage script), I need a way simply observe changes in DOM state. I could set up polling but that seems sloppy.
For a long time, DOM3 mutation events were the best available solution, but they have been deprecated for performance reasons. DOM4 Mutation Observers are the replacement for deprecated DOM3 mutation events. They are currently implemented in modern browsers as MutationObserver (or as the vendor-prefixed WebKitMutationObserver in old versions of Chrome):
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(function(mutations, observer) {
// fired when a mutation occurs
console.log(mutations, observer);
// ...
});
// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
subtree: true,
attributes: true
//...
});
This example listens for DOM changes on document and its entire subtree, and it will fire on changes to element attributes as well as structural changes. The draft spec has a full list of valid mutation listener properties:
childList
Set to true if mutations to target's children are to be observed.
attributes
Set to true if mutations to target's attributes are to be observed.
characterData
Set to true if mutations to target's data are to be observed.
subtree
Set to true if mutations to not just target, but also target's descendants are to be observed.
attributeOldValue
Set to true if attributes is set to true and target's attribute value before the mutation needs to be recorded.
characterDataOldValue
Set to true if characterData is set to true and target's data before the mutation needs to be recorded.
attributeFilter
Set to a list of attribute local names (without namespace) if not all attribute mutations need to be observed.
(This list is current as of April 2014; you may check the specification for any changes.)
Edit
This answer is now deprecated. See the answer by apsillers.
Since this is for a Chrome extension, you might as well use the standard DOM event - DOMSubtreeModified. See the support for this event across browsers. It has been supported in Chrome since 1.0.
$("#someDiv").bind("DOMSubtreeModified", function() {
alert("tree changed");
});
See a working example here.
Many sites use AJAX/XHR/fetch to add, show, modify content dynamically and window.history API instead of in-site navigation so current URL is changed programmatically. Such sites are called SPA, short for Single Page Application.
Usual JS methods of detecting page changes
MutationObserver (docs) to literally detect DOM changes.
Info/examples:
How to change the HTML content as it's loading on the page
Performance of MutationObserver to detect nodes in entire DOM.
Lightweight observer to react to a change only if URL also changed:
let lastUrl = location.href;
new MutationObserver(() => {
const url = location.href;
if (url !== lastUrl) {
lastUrl = url;
onUrlChange();
}
}).observe(document, {subtree: true, childList: true});
function onUrlChange() {
console.log('URL changed!', location.href);
}
Event listener for sites that signal content change by sending a DOM event:
pjax:end on document used by many pjax-based sites e.g. GitHub,
see How to run jQuery before and after a pjax load?
message on window used by e.g. Google search in Chrome browser,
see Chrome extension detect Google search refresh
yt-navigate-finish used by Youtube,
see How to detect page navigation on YouTube and modify its appearance seamlessly?
Periodic checking of DOM via setInterval:
Obviously this will work only in cases when you wait for a specific element identified by its id/selector to appear, and it won't let you universally detect new dynamically added content unless you invent some kind of fingerprinting the existing contents.
Cloaking History API:
let _pushState = History.prototype.pushState;
History.prototype.pushState = function (state, title, url) {
_pushState.call(this, state, title, url);
console.log('URL changed', url)
};
Listening to hashchange, popstate events:
window.addEventListener('hashchange', e => {
console.log('URL hash changed', e);
doSomething();
});
window.addEventListener('popstate', e => {
console.log('State changed', e);
doSomething();
});
P.S. All these methods can be used in a WebExtension's content script. It's because the case we're looking at is where the URL was changed via history.pushState or replaceState so the page itself remained the same with the same content script environment.
Another approach depending on how you are changing the div.
If you are using JQuery to change a div's contents with its html() method, you can extend that method and call a registration function each time you put html into a div.
(function( $, oldHtmlMethod ){
// Override the core html method in the jQuery object.
$.fn.html = function(){
// Execute the original HTML method using the
// augmented arguments collection.
var results = oldHtmlMethod.apply( this, arguments );
com.invisibility.elements.findAndRegisterElements(this);
return results;
};
})( jQuery, jQuery.fn.html );
We just intercept the calls to html(), call a registration function with this, which in the context refers to the target element getting new content, then we pass on the call to the original jquery.html() function. Remember to return the results of the original html() method, because JQuery expects it for method chaining.
For more info on method overriding and extension, check out http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm, which is where I cribbed the closure function. Also check out the plugins tutorial at JQuery's site.
In addition to the "raw" tools provided by MutationObserver API, there exist "convenience" libraries to work with DOM mutations.
Consider: MutationObserver represents each DOM change in terms of subtrees. So if you're, for instance, waiting for a certain element to be inserted, it may be deep inside the children of mutations.mutation[i].addedNodes[j].
Another problem is when your own code, in reaction to mutations, changes DOM - you often want to filter it out.
A good convenience library that solves such problems is mutation-summary (disclaimer: I'm not the author, just a satisfied user), which enables you to specify queries of what you're interested in, and get exactly that.
Basic usage example from the docs:
var observer = new MutationSummary({
callback: updateWidgets,
queries: [{
element: '[data-widget]'
}]
});
function updateWidgets(summaries) {
var widgetSummary = summaries[0];
widgetSummary.added.forEach(buildNewWidget);
widgetSummary.removed.forEach(cleanupExistingWidget);
}

Angular Dynamic form observable property binding

I have a problem with some dynamically generated forms and passing values to them. I feel like someone must have solved this, or I’m missing something obvious, but I can't find any mention of it.
So for example, I have three components, a parent, a child, and then a child of that child. For names, I’ll go with, formComponent, questionComponent, textBoxComponent. Both of the children are using changeDetection.OnPush.
So form component passes some values down to questionComponent through the inputs, and some are using the async pipe to subscribe to their respective values in the store.
QuestionComponent dynamically creates different components, then places them on the page if they match (so many types of components, but each questionComponent only handles on one component.
some code:
#Input() normalValue
#Input() asyncPipedValue
#ViewChild('questionRef', {read: ViewContainerRef}) public questionRef: any;
private textBoxComponent: ComponentFactory<TextBoxComponent>;
ngOnInit() {
let component =
this.questionRef.createComponent(this.checkboxComponent);
component.instance.normalValue = this.normalValue;
component.instance. asyncPipedValue = this. asyncPipedValue;
}
This works fine for all instances of normalValues, but not for asyncValues. I can confirm in questionComponent’s ngOnChanges that the value is being updated, but that value is not passed to textBoxComponent.
What I basically need is the async pipe, but not for templates. I’ve tried multiple solutions to different ways to pass asyncValues, I’ve tried detecting when asyncPipeValue changes, and triggering changeDetectionRef.markForChanges() on the textBoxComponent, but that only works when I change the changeDetectionStrategy to normal, which kinda defeats the performance gains I get from using ngrx.
This seems like too big of an oversight to not already have a solution, so I’m assuming it’s just me not thinking of something. Any thoughts?
I do something similar, whereby I have forms populated from data coming from my Ngrx Store. My forms aren't dynamic so I'm not 100% sure if this will also work for you.
Define your input with just a setter, then call patchValue(), or setValue() on your form/ form control. Your root component stays the same, passing the data into your next component with the async pipe.
#Input() set asyncPipedValue(data) {
if (data) {
this.textBoxComponent.patchValue(data);
}
}
patchValue() is on the AbstractControl class. If you don't have access to that from your question component, your TextBoxComponent could expose a similar method, that can be called from your QuestionComponent, with the implementation performing the update of the control.
One thing to watch out for though, if you're also subscribing to valueChanges on your form/control, you may want to set the second parameter so the valueChanges event doesn't fire immediately.
this.textBoxComponent.patchValue(data, { emitEvent: false });
or
this.textBoxComponent.setValue(...same as above);
Then in your TextBoxComponent
this.myTextBox.valueChanges
.debounceTime(a couple of seconds maybe)
.distinctUntilChanged()
.map(changes => {
this.store.dispatch(changes);
})
.subscribe();
This approach is working pretty well, and removes the need to have save/update buttons everywhere.
I believe I have figured out a solution (with some help from the gitter.com/angular channel).
Since the values are coming in to the questionComponent can change, and trigger it's ngOnChanges to fire, whenever there is an event in ngOnChanges, it needs to parse through the event, and bind and changes to the dynamic child component.
ngOnChanges(event) {
if (this.component) {
_.forEach(event, (value, key) => {
if (value && value.currentValue) {
this.component.instance[key] = value.currentValue;
}
});
}
}
This is all in questionComponent, it resets the components instance variables if they have changed. The biggest problem with this so far, is that the child's ngOnChanges doesn't fire, so this isn't a full solution. I'll continue to dig into it.
Here are my thoughts on the question, taking into account limited code snippet.
First, provided example doesn't seem to have anything to do with ngrx. In this case, it is expected that ngOnInit runs only once and at that time this.asyncPipedValue value is undefined. Consequently, if changeDetection of this.checkboxComponent is ChangeDetection.OnPush the value won't get updated. I recommend reading one excellent article about change detection and passing async inputs. That article also contains other not less great resources on change detection. In addition, it seems that the same inputs are passed twice through the component tree which is not a good solution from my point of view.
Second, another approach would be to use ngrx and then you don't need to pass any async inputs at all. Especially, this way is good if two components do not have the parent-child relationship in the component tree. In this case, one component dispatches action to put data to Store and another component subscribes to that data from Store.
export class DataDispatcherCmp {
constructor(private store: Store<ApplicationState>) {
}
onNewData(data: SomeData) {
this.store.dispatch(new SetNewDataAction(data));
}
}
export class DataConsumerCmp implements OnInit {
newData$: Observable<SomeData>;
constructor(private store: Store<ApplicationState>) {
}
ngOnInit() {
this.newData$ = this.store.select('someData');
}
}
Hope this helps or gives some clues at least.

sails.js - How can I specify an order to the routes of installable hooks?

I have a few policies that I'm trying to convert to installable hooks.
One in particular is the authentication step that adds a session variable for who the user is. I need to ensure that it fires first because subsequent hooks/controllers look at the session to determine who the user is.
The docs on routes ( https://github.com/balderdashy/sails-docs/blob/master/concepts/extending-sails/Hooks/hookspec/routes.md ) say that I can specify if I want to run the route before or after all the custom routes, but I don't see a way to specify one hook before another hook.
I tried adding a "sails.on" in the initialize step of my two hooks as specified in the initialize docs ( https://github.com/balderdashy/sails-docs/blob/master/concepts/extending-sails/Hooks/hookspec/initialize.md ). While it did alter the order of the initialize phase, it didn't seem to have any impact on the order that routes were handled.
Any pointers would be greatly appreciated.
As you noted, there's no way to re-order hooks at the moment, but that doesn't mean you can't accomplish your goal in another way. The routes feature of hooks is very convenient, but in this case you will need to bind your routes using events, and then make your hooks dependent on each other to ensure that the routes load in the correct order. Many of the core Sails hooks work in just this way.
If you want to ensure that the hook firsthook to loads all of its routes before secondhook, you would put the following as the initialize method of firsthook:
initialize: function(cb) {
sails.on('router:before', function () {
sails.router.bind(routePath1, routeFn1);
sails.router.bind(routePath2, routeFn2);
sails.router.bind(routePath3, routeFn3);
etc...
});
}
And then do the same in secondhook, but wrapped in a sails.after block:
initialize: function(cb) {
sails.after('hook:firsthook:loaded', function() {
sails.on('router:before', function () {
sails.router.bind(routePath1, routeFn1);
sails.router.bind(routePath2, routeFn2);
sails.router.bind(routePath3, routeFn3);
etc...
});
}
}
Note that sails.after can accept either a single event name or an array to wait for.

Determine caller in Installable Script

I've create an installable script which creates forms on the fly for 2 to 3 party verification. Since these forms are filled out asynchronously, and often in batches, it is important to determine which form called the function.
First the response form is created, then a trigger is installed.
CreateForm function:
function createForm(title){
var form = FormApp.create(title)
//set parameters for new form
form.setCollectEmail(true);
form.setShowLinkToRespondAgain(false);
...
return form;
};
InstallTrigger function:
function InstallTrigger(form, funct) {
var trigger= ScriptApp.newTrigger(funct)
.forForm(form)
.onFormSubmit()
.create()
return trigger.getUniqueId();
};
During the initial form submit, a function called createMessage() creates an email based on responses and runs the two scripts above. The email contains a link to the newly created form to await approval. To that point, everything works fine.
The problem comes when the newly installed trigger fires. I haven't found a way to set the trigger source as a variable. I'm sure that it has to do with an event, but the documentation on events doesn't go too far into forms from what I can see. I read that it can be done (Understanding Events). I just don't quite understand where (e) is defined on an installable script. Would it be in the install function or some other place?
Thanks again Serge inas for the walkthrough.
(e) is defined when the function defined. In my example above, the InstallTrigger() function adds a trigger to the form passed to it. The script that executes on submission is also passed to it. So, the installation of the trigger comes from a pre-installed onSubmit() trigger. In the submission function, it calls
var NewForm = FormApp.createForm();
InstallTrigger(NewForm, triggerFunction);
The function "triggerFunction" should look something like this:
function triggerFunction (e) {
Logger.log(JSON.stringify(e))
GmailApp.sendEmail("yourEmailString","Debugging",Logger.getLog() //sends an email to you with the logfile.
var form = FormApp.openByUrl(e.response.getEditResponseUrl());
...
}
The e.source mentioned in the aforementioned article says that it works for installable triggers, but when enumerated, only the e.resource and e.authMode were available. Fortunately, the e.response contains the method editUrl that can be used with the method .openByUrl() and return the original form.

Autoscale text input with JEditable.js?

I've been looking for a script that combines the autoGrowInput with the JEditable but found none.
Use https://github.com/MartinF/jQuery.Autosize.Input initialized automatically via jEditable's event data:
jQuery(element).editable(save_fn, {
data: function(value,settings} {
var target = event.target;
window.setTimeout(function(){
jQuery(target).find('input').autosizeInput();
});
return value;
}
});
It's worth noting that this event (data) fires before the input element is actually created, hence the use of the timeout. There doesn't seem to be an event available at the present time for after the input has been created.
Actually I have created a plugin that does exactly that. You can check the demo and the documentation. I tried to make it very intuitive. It has ajax capabilities, using the RESTful philosophy. If you liked the animation effect on the autoGrowInput, it will be really easy to add it to the plugin just by changing the css file, using the transition property.
If I get people to like it, I may be able to improve and add more features to it. Hope it helps.