I have used this package for analytics.
My analytics is working for page view but for click event not working. I have written following code:
analytics.track("click", {
eventName: "downloadImage",
})
I'm not sure exactly what you're doing, but it should work something like this:
Template.myTemplate.events = {
'click button': function (event, template) {
analytics.track("Bought Ticket", {
eventName: "Wine Tasting",
couponValue: 50
});
}
}
What this does is tracks each time the button is clicked as a "Bought Ticket" event.
Related
Example Stencil.js web component:
import { Component, ComponentInterface, Event, EventEmitter, h, Host } from "#stencil/core";
#Component({
tag: 'foo-testwebcomponent'
})
export class TestWebComponent implements ComponentInterface {
#Event({
eventName: 'foo-click',
cancelable: true
}) fooClick: EventEmitter;
fooClickHandler() {
this.fooClick.emit();
}
render() {
return(
<Host>
<a href="#"
onClick={this.fooClickHandler.bind(this)}
>Testing</a>
</Host>
)
}
}
HTML:
<foo-testwebcomponent id="test"></foo-testwebcomponent>
<script>
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('test')
.addEventListener('foo-click', event => {
event.preventDefault();
console.log(`Foo Test Web Component clicked!`);
});
});
</script>
Problem:
In the HTML implementation, the prevent default does not stop the link from working.
Question:
How can I allow the end-user of my web component to prevent default, and stop the link from working?
I know that I can add preventDefault() in the fooClickHandler() (see below), but that seems odd to me. I'd like to give the control to the end user of the web component.
#Event({
eventName: 'foo-click',
cancelable: true
}) fooClick: EventEmitter<MouseEvent>;
fooClickHandler(event: MouseEvent) {
event.preventDefault();
this.fooClick.emit();
}
There are two separate events:
The user-initiated click event
Your fooClick custom event
In your example you call preventDefault() on the custom event but you need to call it on the original click event to prevent the link from navigating.
I know of two ways to achieve this:
1: Track whether your custom event is canceled
You can check whether the user called preventDefault() on your custom event using the defaultPrevented property. The fooClick event handler can stay the same.
fooClickHandler(clickEvent: MouseEvent) {
const customEvent = this.fooClick.emit();
if (customEvent.defaultPrevented) {
clickEvent.preventDefault();
}
}
Check out this online demo.
2: Pass the click event
Pass the click event to the fooClick event handler so the user can cancel it.
fooClickHandler(clickEvent: MouseEvent) {
this.fooClick.emit({ originalEvent: clickEvent });
}
And in the handler:
element.addEventListener('foo-click', event => {
event.detail.originalEvent.preventDefault();
console.log(`Foo Test Web Component clicked!`);
});
One way would be to overload the addEventListener function and capture the function reference
(needs some more work to make it work with nested elements, you get drift)
Or use a custom method addClick(name,func) so the user can still add any listener
<script>
customElements.define(
"my-element",
class extends HTMLElement {
connectedCallback() {
this.clicked = (evt)=>{
document.body.append("component handler")
}
this.onclick = (evt) => {
this.clicked(evt);
}
}
addEventListener(name, func) {
this.clicked = func;
}
}
);
document.addEventListener('DOMContentLoaded', () => {
document.querySelector('my-element')
.addEventListener('click', event => {
document.body.append(`user handler`);
});
});
</script>
<my-element>Hello Web Components World!</my-element>
You could also use good old onevent handlers:
<script>
customElements.define(
"my-element",
class extends HTMLElement {
connectedCallback() {
this.onclick = (evt) => console.log("component handler")
}
}
);
document.addEventListener('DOMContentLoaded', () => {
let el = document.querySelector('my-element');
el.onclick = event => console.log(`user handler`, el.onclick);
});
</script>
<my-element onclick="console.log('inline')">Hello Web Components World!</my-element>
I have a specific unified alert package that displays alerts/notifications upon submission in a cohesive way across web browsers. I am finding that after submit in the Autoform.hook(), the default browser alert format also fires. Any help to prevent the default browser alter from firing would be appreciated.
I have tried using an event handler:event.preventDefault();
AutoForm.hooks({
'edit-form': {
onSuccess: function (operation, result, template) {
IonPopup.alert({
title: 'Saved Succesfully!',
subTitle: 'Please Click OK to go back',
onOk: function()
{
Session.set("editingReqEvent", null);
Router.go('calendar');
}
});
},
onError: function(operation, error, template) {
IonPopup.alert({title: 'Save Unsucessful!', subTitle: 'Please go back and check entries'});
console.log(error);
}
}
});
You can disable the default alert event, or overwrite it just with plain js:
window.alert = function() {};
I'm working on an example CRUD application with Meteor.js and am not sure how best to empty out the fields of a form. I need it in two places: when the Submit button is clicked, and when the Cancel button is clicked.
I implemented it this way by creating a utility function called clearFormFields() that just uses jQuery to empty their contents, but it doesn't feel as "Meteoric" as it should; I feel it should be scoped better so it doesn't have a global visibility. What am I doing wrong?
function clearFormFields() {
$("#description").val("");
$("#priority").val("");
}
Template.todoNew.events({
'click #cancel': function(event) {
event.preventDefault();
Session.set('editing', false);
clearFormFields();
},
'submit form': function(event) {
event.preventDefault();
var theDocument = {
description: event.target.description.value,
priority: event.target.priority.value
};
if (Session.get("editing")) {
Meteor.call("updateTodo", theDocument, Session.get('theDocumentId'))
}
else {
Meteor.call("insertTodo", theDocument);
}
Session.set('editing', false);
clearFormFields();
/* Could do this twice but hate the code duplication.
description: event.target.description.value = "";
priority: event.target.priority.value = "";
*/
}
});
You could use the native reset method of the DOM form node ?
"submit form":function(event,template){
event.preventDefault();
// ...
template.find("form").reset();
}
http://www.w3schools.com/jsref/met_form_reset.asp
The DOM object that originated the event can be accessed and reset from through event.target.reset();
"submit form":function(event){
event.preventDefault();
//...
event.target.reset();
}
http://docs.meteor.com/#/full/eventmaps
I'm developing a keno game. When the user presses the start button a Meteor.Call() executes everything for that card pick. Including updating the user balance. I have a setTimeout for the winning numbers, so that they display over a period of about 20 seconds. The problem is that when the call is made, the balance updates instantly, and then the numbers start displaying with the delay. I not familiar with how to solve this. I appreciate any help.
server-side:
Meteor.methods({
process: function(){
// generate numbers
// update user balance
}
});
client-side:
Template.keno.events({
'click #start' : function(){
Meteor.call('process',function(err,numbers){
//setTimeout on displaying numbers
// as setTimeout displays numbers, balance already updated. I need to delay
// the balance update, until all numbers are displayed.
// otherwise, the player see that they won before all numbers come out.
});
}
});
** Update **
The only help I need is to understand how to make a variable like {{balance}} unreactive, until I finish the setTimeout, and then have it update. Should I be using sessions? Should I not use a template variable and instead, insert the balance with jquery? It's just a simple solution, the difficulty is that I don't know what function / method I'm looking for that can help me turn off the reactivity for a set amount of time, and then update, after the Meteor.call() for then numbers finishes it's setTimeout.
If I understand your situation correctly, you need the template {{balance}} expression to be set at a time you decide vs. when the collection gets a result from the server. So you could use Session to set a value when you like. Below is an example:
<body>
{{> game}}
</body>
<template name="game">
<button id="process">Process</button>
<div>{{firstNumber}}</div>
<div>{{secondNumber}}</div>
<div>balance: {{balance}}</div>
</template>
if (Meteor.isClient) {
Template.game.events({
'click #process': function (e, tmpl) {
Meteor.call('process', function (err, result) {
Session.set('firstNumber', result[0]);
setTimeout(function () {
Session.set('secondNumber', result[1]);
Session.set('balance', result[0] + result[1]);
}, 2000);
});
}
});
Template.game.helpers({
firstNumber: function () { return Session.get('firstNumber'); },
secondNumber: function () { return Session.get('secondNumber'); },
balance: function () { return Session.get('balance'); }
});
}
if (Meteor.isServer) {
function randomNumber () {
return Math.floor(Math.random() * 100);
}
Meteor.methods({
process: function () {
return [randomNumber(), randomNumber()];
}
});
}
Try to wrap your Meteor.call() inside the setTimeout() itself, like:
Template.keno.events({
'click #start' : function(){
setTimeout(function(){
Meteor.call('process',function(){
//do something.
});
}, 20000);
}
});
Maybe the solution is to use reactivity on a duplicated collection :
You set your main collection on server side only.
You create another collection on the client side that will be a duplicate collection but used only for display
Then you pusblish the main collection to the client.
On the client side, you set all required observer on it that will replicate all modification on the duplicated collection. But this way you can manage animation or any other wished features. All actions on client side will do call on server-side but it won't affect immediatly the templates because the templates only use the duplicated collections.
I hope it will help you.
OK, so I threw this demo together in 5 mins, works though.
Here's the demo: http://keno-test.meteor.com/
Of course it needs LOT's more work, but the delayed thing works.
HTML:
<head>
<title>keno-test</title>
</head>
<body>
{{> hello}}
</body>
<template name="hello">
<input id="callCardThing" type="button" value="Start card-thing" />
<h1>Here are the cards!</h1>
<ul>
{{#each cards}}
<li>{{value}}</li>
{{/each}}
</ul>
</template>
JS:
Cards = new Meteor.Collection('cards');
if (Meteor.isClient) {
Deps.autorun(function () {
Meteor.subscribe("cards");
});
Template.hello.events({
"click #callCardThing": function (event) {
Meteor.call("doCardThingOnServer");
}
});
Template.hello.helpers({
cards: function () {
return Cards.find({});
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
Meteor.publish("cards", function () {
return Cards.find({});
});
});
Meteor.methods({
doCardThingOnServer: function () {
// I remove all the cards every time just for the demo…
Cards.remove({});
var numberOfcards = 10;
var counter = Meteor.setInterval(function () {
Cards.insert({value: 'whatever! no: '+numberOfcards });
numberOfcards--;
if (numberOfcards < 1) Meteor.clearInterval(counter);
}, 1500);
}
});
}
Ok, so how about conditional {{balance}} rendering?
var shouldRender = false;
setTimeout(function () {
shouldRender = true;
}, 2000);
Template.template_name.shouldRender = function () {
return shouldRender;
}
{{#if shouldRender}}
{{>balance}}
{{/if}}
Have a look at the Atmosphere animation package : https://atmosphere.meteor.com/package/animation!
I've just done this package to explore one way of doing animation on database reactivity.
You have to register a cursor and the template to animate. There is a project that will show you how to do that.
I hope it will help you.
JqueryUI:
The code below fires an alert every time the box is closed, but how can I make it so it only does this for once and not every time.
$("#box").dialog({
close: function () {
alert(999);
}
});
This was how I did it before using jQueryUi:
$("#box").one("click", function () {
alert(999);
return false
});
According to the docs, the .close() method also has a corresponding event: dialogclose. So you should be able to do this:
$("#box").one("dialogclose",function() {
alert(999);
});