How to override v-on:click in vue for logging purposes - vue.js

Looking to implement some logging with the purpose of generating some usage statistics for a web application written with Vue.
I want to avoid writing an explicit 'log' statement within or with every 'on click' callback.
Is it possible to wrap/override the v-on:click directive to first perform logging, then execute the callback?

As far as I know it is not possible to do it for all v-on:clicks at the same time. As the event handlers are connected to the specific elements you would need to do it for every element separately.
Instead you can add an eventlistener for click events like this:
window.addEventListener('click', e => console.log(e))
or like this
document.onclick = e => console.log(e)
Note that this will log every single click, even if it's not on an element with v-on. The event here gives you the source element that was clicked, that you might be able to use to define if the click is relevant for your logging or not.

This previous post could work for you:
Extend vueJs directive v-on:click
A wrapper component for you click event elements.

Related

How do I hook into the blur event of the v-currency-field?

I'm writing a vue.js application with the v-currency-field package: https://www.npmjs.com/package/v-currency-field
When I read the documentation, I see nothing for a blur event (or any events at all): https://phiny1.github.io/v-currency-field/started.html#introduction
I'm getting around this by selecting the input inside the v-currency-field like this:
const holdbackAmountInput = document.querySelectorAll('[aria-label="Holdback amount"]')[0];
holdbackAmountInput.addEventListener('blur', this.holdbackAmountInputBlurHandler);
But is there not a better way to do this? It gets more complicated than the above code because I have to run it in the updated() hook and check if the holdbackAmountInput exists, and if it does, I have to assign it to a data object so that I have a reference to it when I have to remove the event listener when it's removed from the DOM or when the component is destroyed. Seems needlessly complicated for something that should be really simple.
Is there not a simpler way to do this?

see the list of event listeners currently attached

I want to check the list of event listeners that are added. For example, I used the code cy.on('pan zoom resize', update); and added function called update in for loop. I do this many times. I also call cy.off('pan zoom resize', update); to remove the event listeners but I want to be sure about it.
The only think I can think of is using console.log but this method might not be helpful.
I also think that in some places people forgot to remove the event listeners and just always added. With too many repetitions this might cause problems.
There is a data field in the private cytoscape object called listeners. You can see that if you:
console.log() the cy object,
navigate to _private,
then open the emitter object
and lastly go to listeners
This is the array listing all the default and user defined event listeners with some metadata like the event, type and scope of the listener.
You can access this in your code by simply calling
cy.emitter().listeners
The question now is, why do you need this information in the first place? Normally, you should be just fine if you call cy.off('eventXY', ...) before using any cy.on('eventXY', ...). Are you sure you need this for your application to work? Maybe elaborate more on the core problem (why you want these information in the first place).
Thanks and have a great day!

Load options on the first open of the Async drop down menu

When I provide loadOptions to an Async control it loads options on mount.
If I pass autoload={false} then it doesn't load options neither on mount nor on open. But it loads options on the first close (or type, or blur).
If I pass onCloseResetsInput={false} then it doesn't load options until I type something. (showing "Type to search" in the menu)
Async provides onOpen handler, but I didn't find the way to use it in this situation. (and react-select#2.0.0-alpha.2 doesn't have it)
So the user needs to type a character, then delete it, to see the full list of options.
How can this be avoided?
Example sandbox: https://codesandbox.io/s/mjkmowr91j
Solution demo: https://codesandbox.io/s/o51yw14l59
I used the Async options loaded externally section from the react-select repo.
We start by loading the options on the Select's onFocus and also set the state to isLoading: true. When we receive the options we save them in the state and render them in the options.
I also keep track of optionsLoaded so that only on the first focus do we trigger the call to get options.
In our use case, we have several of these select inputs on a single page, all async, so the requests to the server will pile up, and are completely unnecessary in a lot of cases (users won't even bother clicking).
I found a workaround for this issue that'll work for my use case on 2.0.0-beta.6:
Include defaultOptions
Add 2 members to your class that will store the resolve/reject methods for the promise.
In your loadOptions function, check if the input is '', if so, create a new promise, and store the values of resolve/reject within your class members, and return that promise. Otherwise, just return the promise normally to get your results.
Add an onFocus handler, and within it call the function to get your results, but also add .then and .catch callbacks passing the resolve and reject functions you stored previously.
Essentially, this makes react-select think you're working on getting the results with a long-running promise, but you don't actually even try to load the values until the field is selected.
I'm not 100% positive there aren't any negative side effects as I just wrote this, but it seems like a good place to start.
Hope this helps someone. I may submit a feature request for this.
In order to load options when user focus first time, set defaultOptions={true}
Thanks, Alexei Darmin for the solution, I was struggling with this... while testing it I converted the solution to a react functional component and added real API fetching.
Here is a working demo, I hope it helps someone

Cycle.js/xstream click event streamed once, but fired twice

There's a single button element on the page and the following click stream:
let submitClick$ = sources.DOM.select(buttonSel)
.events("click")
.mapTo(true)
.debug(console.log)
Once I click on the button, true is logged, which is correct.
However, when I map the stream, the code inside runs twice:
let submitDeal$ = submitClick$.map(() => {
console.log("Clicked")
// ...
})
No other event handlers should be attached to the button, and the element itself sits inside a div:
button(".btn--add", "Submit")
The usual event.preventDefault() and event.stopPropagation() doesn't make a difference, and inspecting the event does show that it is fired from the same element button.btn--add.
Not really sure what's going on, any ideas are appreciated! Thanks!
Versions:
"#cycle/dom": "^12.2.5"
"#cycle/http": "^11.0.1"
"#cycle/xstream-run": "^3.1.0"
"xstream": "^6.4.0"
Update 1: I triple checked and no JS files are loaded twice. I'm using Webpack that bundles a single app.js file that's loaded on the page (Elixir/Phoenix app). Also when inspecting the button in the Event Listeners tab in Chrome's Developer Tools, it seems that only 1 event handled is attached.
Update 2: Gist with the code
Too little information is given to resolve this problem. However some things come to mind:
You shouldn't use .debug(console.log) but .debug(x => console.log(x)) instead. In fact .debug() is enough, it will use console.log internally.
Then, is the button inside a <form>? That may be affecting the events. In general this question needs more details.
Turns out this was due to a bug in xstream, which was fixed in xstream#7.0.0.

Seaside calling a component inside javascript

I have a seaside application with a master-detail page. The master page has a table that consists of a list of tr records. When the user clicks a particular tr element, I want to call a detail component, which'll show the individual record's data.
Since I cannot make a tr element with callback or have it contain an anchor with a callback, I want the tr's onClick property to have some JavaScript which'll call: subcomponent . When I tried this, I got an error saying call: can only be used in callbacks and tasks.
Using ajax is a workaround, however it breaks the back button.
Edit:
More generally, I'd like to know how to set callback like behaviour for various JavaScript events.
Well, you cannot render a component in a tr element, but you could add some anchor or other element in one of its td children.
For my project I did roughly the following: I added an anchor to each row with a special css class, e.g. '.dblclick-action'. This anchor has a normal Seaside callback.
Then I bound a dblclick handler to the tr element that does something like document.location=$(this).find('.dblclick.ction').get(0).href;
I am not close to a Smalltalk image now to give you source code, but I hope you get the idea: you don't use Ajax to click the link in that particular row, but instead have the browser navigate to the callback that is associated to the link in that row. You could say you use the tr.'s dblclick handler to click the link and then let the normal Seaside stuff do its work. No magic there. You can find a little bit more info here.
If you don't want the anchor to be visible you may want to experiment with making the anchor invisible (display: none) or the like.
If you are a bit more experiment friendly, you can also try saving a callback on the server and render its url with callback id as an attribute of the tr element and use the dblclick handler to follow the link from that attribute you extract the value of an attribute in query using attr().
I forgot to answer your initial question: you cannot issue a call: from javascript. But you can use the document.location trick to re/misuse an existing link to a callback on the page using the technique I described in my first answer.